리액트 프로젝트가 하루 앞으로 다가왔다.
당장 내일부터 프로젝트를 만들어 나가야하는데 리액트랑 아직도 안 친하다.
아니 그냥 남 보다 못한 것 같다.
아 나는 useState 밖에 몰라. 망했어요라고 하고 다니면서
진짜 겨우겨우 카운트 +/- 하는게 전부였는데
아니 근데 얘 시켜보니까.. 글쎄 useState 1도 모르던데요..?
...
아오 진짜 나놈 흠씬 맞아
const [state, setState] = useState(초기값);
useState는 컴포넌트에 state 변수를 추가할 수 있는 리액트 훅입니당. (공식문서 曰)
얘는 두개의 값을 가진 배열을 반환한다.
state (== 첫번째 렌더링 중에 전달한 initialState)const handleFunc = () => {
setValue('변경할 값');
setNumber((prevNum) => prevNum + 1)
// 이때 전달되는 함수는 +순수+ 해야하고, 대기중인 state를 유일한 인수로 사용해야함.
// 다음 state를 반환시켜줘야 해!
}
구래구래. let, const같은 변수에 값을 담아서 상태를 변화시켜보자.
일단 예제는 제일 쉽고 많이 만들어보는 카운터로 맹글어보자.
let count = 0;
const handlePlusNum = () => {
count = count + 1;
console.log(count);
};
const handleMinusNum = () => {
count = count - 1;
console.log(count);
};
return (
<>
<p>현재 카운트: {count}</p>
<button onClick={handlePlusNum}>+</button>
<button onClick={handleMinusNum}>-</button>
</>
);
아무리 + / - 버튼을 클릭해도 화면은 미동조차 없다.
근데 handle~ 함수에 찍어놓은 로그에는 숫자 증/감이 잘 찍히고 있는게 확인되었다.

오잉? 값은 잘 변하네? 근데 왜 화면은 그대로인거지?
위에서 보았다시피, 일반 변수는 값이 변경되어도 렌더링을 일으키지 않는다.
리액트에서는 state가 변경되어야만 렌더링이 일어나고 화면이 바뀌게 된다.
고로 state를 변경시켜주는 useState를 사용해야만 한당.
이것저것 예제를 만들어보면서 useState를 익혀보는데
그는.. 내가 원하는 대로 움직이지 않는..쉽지않은 놈이었다
리액트가 작동하는 방식은
비동기식
(정확하게는setState가 비동기로 작동한다)
1. count에 업데이트 된 state값으로 virtualDOM 생성
2. 현재 state 값의 엘리먼트 트리와 버츄얼 돔 비교하기
3. 업데이트가 필요한 state에만 DOM 적용하고 렌더링
사실 이렇게 글로만 보면 나는 잘 모르겠다ㅎ 바보
직접 예제를 만들면서 알아보자
const [count, setCount] = useState(0);
const handlePlusNum = () => {
setCount(count + 1);
};
const handleMinusNum = () => {
setCount(count - 1);
};
return (
<>
<p>현재 카운트: {count}</p>
<button onClick={handlePlusNum}>+</button>
<button onClick={handleMinusNum}>-</button>
</>
);
여기서 만약, handlePlusNum을 +1이 아니라 막 3씩 늘리고 싶다고 쳐보자.
const handlePlusNum = () => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
};
이렇게 내가 급발진해서 count +1 쿠다사이쿠다사이쿠다사이 해도

응 안돼 +1 만 해줄거야
😦
이게 setState가 연속으로 호출됐을때 batch update한다는 그거였구나
하나의 state에 여러번 setState를 업데이트 실행했을 땐, 가장 최신의 state값만 적용해준다.
만약 setTimeout을 걸어보면?
const handlePlusNum = () => {
setCount(count + 1);
console.log(count);
setTimeout(() => {
setCount(count + 100);
console.log(count);
}, 500);
};

여기서도 batch update가 이루어진다.
하나의 컴포넌트 / 페이지 / 컴포넌트에 많고 많은 state들이 있을텐데, 그 수많은 상태들이 각각 바뀔 때마다 화면을 계속 리렌더링 시켜줘야 한다면 성능에도, 일관성에도 문제가 생길 것이다.
그래서 리액트가 이런 문제들을 효율적으로 해결하기 위해서 setState를 저렇게 연속적으로 호출해도 취합해서 한번에 렌더링 시켜주는 방법을 택한 것이라고 한다.
리액트의 state는 객체다!
그러므로, 동일한 key에 대해서 이전의 값을 계속 덮어 쓰고 있는 것 아니느냐뇽?
그럼 결국엔 가장 최신의 값을 갖게 된다
쏠쑤이써!!!
할쑤이써@@
setState 함수의 인자로 콜백함수 사용 const handlePlusNum = () => {
setCount((count) => count + 1);
setCount((count) => count + 1);
console.log(count);
};

+버튼 한번 클릭 할 때마다, +2씩 잘 증가함!
useEffect 훅 사용사실 useEffect 잘 모른다.
안 써봤다.
그래요. 몰라요. ㅠ 그래도 써볼게요..
🙁
근데 아까부터 콘솔에 로그를 찍어보는데 화면과 콘솔이 싱크가 안 맞는다.
화면에는 count가 12로 찍혀있는데 콘솔엔 아직 10이 찍혀있는 상황.
이 또한 setState 의 비동기적 특성때문에 발생하는 현상 🤔
// 내가 기대한 작동 방식...
const handlePlusNum = () => {
setCount(count + 1); // 상태를 즉시 업데이트
console.log(count); // 업데이트된 값이 콘솔에 찍히겠지!
// 응 아냐.. 업데이트 이전의 값이 찍혀부러..😗
};
그래서 상태 변경 후의 정확한 값이 필요해. 라고 한다면
useEffect를 사용하여 상태 변경을 추적할 수 있다고한다.
useEffect(() => {
console.log(count); // 상태가 업데이트될 때마다 최신 count 값 출력
}, [count]);

화면과 일치하게 잘 찍힌다 🤗
useState (정확히는setState )는 비동기적으로 작동한다state 가 많을 수록 리렌더링이 잦아짐 > 속도 🔽 + 성능 🔽