React | useState 진짜 알고있냐 지두팔

지두팔·2024년 8월 25일

💙React

목록 보기
1/1

리액트 프로젝트가 하루 앞으로 다가왔다.
당장 내일부터 프로젝트를 만들어 나가야하는데 리액트랑 아직도 안 친하다.
아니 그냥 남 보다 못한 것 같다.

아 나는 useState 밖에 몰라. 망했어요 라고 하고 다니면서
진짜 겨우겨우 카운트 +/- 하는게 전부였는데

아니 근데 얘 시켜보니까.. 글쎄 useState 1도 모르던데요..?
...

아오 진짜 나놈 흠씬 맞아

useState

const [state, setState] = useState(초기값);

useState는 컴포넌트에 state 변수를 추가할 수 있는 리액트 훅입니당. (공식문서 曰)

얘는 두개의 값을 가진 배열을 반환한다.

  • 현재 state (== 첫번째 렌더링 중에 전달한 initialState)
  • setSomething(nextState) == set 함수 (state를 다른 값으로 업데이트 해주고, 리렌더링을 촉발시킴)
    • set함수에서 state를 직접 전달하거나, 이전 state로부터 계산한 함수를 전달할 수도 있음.
const handleFunc = () => {
	setValue('변경할 값');
    setNumber((prevNum) => prevNum + 1)
  	// 이때 전달되는 함수는 +순수+ 해야하고, 대기중인 state를 유일한 인수로 사용해야함.
    // 다음 state를 반환시켜줘야 해!
}

🤔 변수를 쓰면 되는거아냐? 왜 귀찮게 useState까지 써야돼?

구래구래. 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가 변경되어야만 렌더링이 일어나고 화면이 바뀌게 된다.
고로 state를 변경시켜주는 useState를 사용해야만 한당.

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);
  };

  1. 최초 count = 0 출력됨.
  2. 그 다음 count = 1 출력되고, 1 + 100 인 101 이 출력..
    될 줄 알았으나 그냥 100이 나옴. 😅
  3. 그 다음도 가장 마지막인 +100만 되어서 200, 그 이후도 300, 400....

여기서도 batch update가 이루어진다.

하나의 컴포넌트 / 페이지 / 컴포넌트에 많고 많은 state들이 있을텐데, 그 수많은 상태들이 각각 바뀔 때마다 화면을 계속 리렌더링 시켜줘야 한다면 성능에도, 일관성에도 문제가 생길 것이다.

그래서 리액트가 이런 문제들을 효율적으로 해결하기 위해서 setState를 저렇게 연속적으로 호출해도 취합해서 한번에 렌더링 시켜주는 방법을 택한 것이라고 한다.

리액트의 state는 객체다!
그러므로, 동일한 key에 대해서 이전의 값을 계속 덮어 쓰고 있는 것 아니느냐뇽?
그럼 결국엔 가장 최신의 값을 갖게 된다

🧐 그럼, 동기적으로 처리할 수도 있어?

쏠쑤이써!!!
할쑤이써@@

1. setState 함수의 인자로 콜백함수 사용

  const handlePlusNum = () => {
    setCount((count) => count + 1);
    setCount((count) => count + 1);
    console.log(count);
  };

+버튼 한번 클릭 할 때마다, +2씩 잘 증가함!


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 가 많을 수록 리렌더링이 잦아짐 > 속도 🔽 + 성능 🔽
    • 여러 상태 업데이트를 하나의 업데이트로 묶어 여러개의 setState 호출이 한 번에 처리되도록 하기 위해서.
  • 동기적으로 작동하게 할 수도 있다.
    • setState 함수의 인자로 콜백함수 넣기
    • useEffect의 의존성 활용하기
      ㄴ> 근데 이거. 솔직히 아직 잘 모르겠다. 공부해!
profile
후론트엔드 개발자를 꿈꿔요 💭

0개의 댓글