이 글은 노마드 코더님의 React 강의를 학습한 내용을 기반으로 작성합니다.
state는 기본적으로 데이터가 저장되는 곳이다.
우리가 현재 하고자 하는 것은 React JS를 활용해 다음 사진과 같이 버튼을 클릭할 때마다 숫자가 증가하는 결과물을 생성하는 것이다.
현재 코드는 다음과 같다.
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
const Container = () => (
<div>
<h3>Total clicks: 0</h3>
<button>Click me</button>
</div>
);
ReactDOM.render(<Container />, root); // container를 root 안에 랜더링
</script>
</html>
결과물을 생성하기 위해 두 가지 방법이 존재한다.
하나는 좋지 않은 방식이고 나머지 하나는 우리가 해야 할 최고의 방식이다.
먼저 좋지 않은 방식으로 수행해보며 우리에게 무엇이 필요하며, 어떤 걸 해야 되는지 이해한다.
첫 번째 방식
첫 번째 방식 #1
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function countUp() {
counter = counter + 1;
}
const Container = () => (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={countUp}>Click me</button>
</div>
);
ReactDOM.render(<Container />, root); // container를 root 안에 랜더링
</script>
</html>
첫 번째 방식 #1 결과
: 아무리 버튼을 클릭해도 UI가 업데이트되지 않는다.
이러한 문제가 발생하는 이유는 컴포넌트를 단 한번만 렌더링 하기 때문이다.
즉, 이러한 문제를 해결하기 위해서는 버튼이 클릭되어 counterUp 메서드가 호출될 때마다 Container 컴포넌트를 리렌더링 해야 한다.
#1 문제 해결
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function countUp() {
counter = counter + 1;
render();
}
function render() {
ReactDOM.render(<Container />, root);
}
const Container = () => (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={countUp}>Click me</button>
</div>
);
render();
</script>
</html>
#1 문제 해결 결과
주의!
버튼이 클릭되어 counterUp 메서드가 호출될 때마다 render() 함수를 호출하므로 새로운 Container 컴포넌트 전체를 계속해서 생성될 거라고 생각할 수 있다.
하지만 그렇지 않다. React의 경우 우리가 새로 렌더링하더라도 Container 컴포넌트 전체를 전부 재생성할 필요 없이 바뀐 부분만 새로 생성할 수 있도록 도와준다.
두 번째 방식 setState
첫 번째 방식에는 아쉬운 점이 존재한다.
데이터가 변경될 때마다 render() 함수를 잊지 않고 호출해줘야 한다는 것이다.
그래서 React 에서는 첫 번째 방식보다 더 나은 방법인 setState()를 제시해준다.
setState()는 React.js 어플 내에서 데이터를 보관하고 자동으로 리렌더링을 수행한다.
두 번째 방식 #1 useState();
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function App() {
const data = React.useState();
console.log(data);
return (
<div>
<h3>Total clicks: 0</h3>
<button>Click me</button>
</div>
);
}
ReactDOM.render(<App />, root); // App을 root 안에 랜더링
</script>
</html>
두 번째 방식 #1 결과
React.useState() 결과로 undefined 값과 함수를 지닌 배열을 받게 된다.
이때 undefined 값이 data이고, 함수 f는 data 값을 바꿀 때 사용하는 함수에 해당한다.
물론, 첫 번째 인자에 초기값을 부여할 수 있다.
즉, useState()는 이전에 우리가 작성한 다음 코드를 대신한다.
두 번째 방식 #2
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function App() {
let [counter, modifier] = React.useState(0);
const onClick = () => {
counter = counter + 1;
console.log(counter);
};
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App />, root); // App을 root 안에 랜더링
</script>
</html>
두 번째 방식 #2 결과
: counter값이 정상적으로 증가하는 것을 확인할 수 있다.
두 번째 방식 #3
<!DOCTYPE html>
<html>
<head> </head>
<body>
<div id="root"></div>
</body>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = document.getElementById("root");
let counter = 0;
function App() {
const [counter, setCounter] = React.useState(0);
const onClick = () => {
setCounter(counter + 1);
};
return (
<div>
<h3>Total clicks: {counter}</h3>
<button onClick={onClick}>Click me</button>
</div>
);
}
ReactDOM.render(<App />, root); // App을 root 안에 랜더링
</script>
</html>
두 번째 방식 #3 결과
: 보다시피 counter 값만 리렌더링 되는 것을 확인할 수 있다.
(React.js는 오로지 바뀐 부분만을 업데이트해준다.)
번외
React JS와 바닐라 JS 결과를 비교해보면
React JS의 경우 버튼을 클릭할 때마다 UI에서 바뀐 부분만 업데이트하는 반면,
바닐라 JS는 span 전부가 업데이트되는 것을 확인할 수 있다.
이것은 매우 중요한 기능이다.
'React > State' 카테고리의 다른 글
Final Practice and Recap (0) | 2022.07.27 |
---|---|
State Practice (0) | 2022.07.26 |