치춘짱베리굿나이스

prevState 사용 이유 본문

ClientSide/React

prevState 사용 이유

치춘 2022. 5. 4. 13:13

prevState 사용 이유

const [testValue, setTestValue] = useState(false);
...
setTestValue(!testValue);

우선 아무 생각 없이 현재 상태값을 그대로 가져와서 이렇게 작성하던 과거의 나를 반성하자

쓰는 법

const [testValue, setTestValue] = useState(false);
...
setTestValue((prevState) => !prevState);

간단하다

setState() 함수 내에 인라인 함수를 작성하면 된다

인자로 prevState가 자동으로 들어간다

근데 왜 굳이 써요?

const [testValue, setTestValue] = useState(0);

  const handleOnClick = () => {
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
  };

...
<div>{`${testValue}`}</div>
<div onClick={handleOnClick}>add 1</div>

앞의 경우는 상태값이 true, false 두 가지 경우밖에 없기 때문에 와닿지 않을 수 있다

한 번의 클릭으로 상태값이 5번 바뀐다고 정의해보자

클릭할 때마다 값이 5씩 증가할 것 같은 비주얼이다

하지만 우리의 예상은 보기좋게 빗나갔다

마치 5씩 증가할것 같다고 예상한 우리들을 비웃듯 한 번의 클릭당 값이 1씩만 증가하는 것을 볼 수 있다

왜 그런 건가요

함수에는 setTestValue가 순서대로 5줄 적혀있기 때문에 슬쩍 보기엔 5개의 setTestValue가 순서대로 실행될 것만 같다. 하지만 setState는 비동기로 작동한다, 그 말인 즉슨 5개의 setTestValue가 서로를 기다려주지 않는다는 것

따라서 testValue가 각각의 setTestValue에서 바뀌었더라도 다른 setTestValue는 그것을 모르며, 단지 리액트에게 “현재 testValue에서 값을 1 더해서 저장해 줘" 라는 요청만을 할 뿐이고, 리액트는 이 요청들을 모아 값을 한번에 갱신한다

한줄요약: setState는 상태값을 바꾸라는 요청을 할 뿐이지 실제로 상태값을 바꿔주진 않으며, 값을 바꿔주는건 리액트가 알아서 한다

⇒ 마지막에 요청되는 변경 사항으로 요청이 오버라이딩 된다

요청이 오버라이딩 된다구여?

const [testValue, setTestValue] = useState(0);

  const handleOnClick = () => {
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 3);
  };

...
<div>{`${testValue}`}</div>
<div onClick={handleOnClick}>add 1</div>

마지막에 요청되는 변경 사항으로 오버라이딩 된다 라는 게 무엇인지 위의 예시를 보자

위의 4개의 setTestValue는 기존의 testValue에서 1을 더해주고, 나머지 1개의 setTestValue는 기존의 testValue에서 3을 더해준다

결과값이 어떻게 될까

값이 맨 마지막에 정의된 대로 3씩 증가한다

const [testValue, setTestValue] = useState(0);

  const handleOnClick = () => {
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
    setTestValue(testValue + 3);
    setTestValue(testValue + 1);
    setTestValue(testValue + 1);
  };

...
<div>{`${testValue}`}</div>
<div onClick={handleOnClick}>add 1</div>

이렇게 3을 더해주는 요청이 중간에 위치한다면 어떻게 될까?

다시 1씩 증가하는 것을 볼 수 있다

setTestValue 5개가 각각 비동기적으로 (병렬적으로) 처리되긴 하지만, 마지막으로 들어온 요청으로 덮어씌워지는구나! 라고 생각하면 쉬울 것 같다

그래서 prevState는 뭔데요?

위와 같이 비동기적으로 setState가 수행되는 것 때문에, 직전 state값을 가지고 작업을 하려고 하면 원하는 대로 값이 잘 변하지 않을 때가 있다

이때 prevState를 사용하면 나름 동기적으로 작업을 수행할 수 있다

const [testValue, setTestValue] = useState(0);

  const handleOnClick = () => {
        setTestValue(prevState => prevState + 1);
    setTestValue(prevState => prevState + 1);
    setTestValue(prevState => prevState + 1);
    setTestValue(prevState => prevState + 1);
    setTestValue(prevState => prevState + 1);
  };

...
<div>{`${testValue}`}</div>
<div onClick={handleOnClick}>add 1</div>

앞의 코드를 prevState를 이용하여 바꿔보자

setTestValue 안에 인자를 받는 함수를 사용하면 되고, 인자에는 prevState 값이 자동으로 들어가므로 이름은 어떻게 해도 상관없지만 기왕 이쁘게 하자

드디어 우리가 예상했던 대로 값이 5씩 증가한다

setState가 리액트 측에 요청을 보낼 때, 앞에서는 “testValue에 1을 더해주세요" 라고 요청을 보냈지만, 이번에는 “이전 상태값에 1을 더해주세요" 라는 요청을 보냈기 때문에 오버라이딩 되지 않고 요청된 순서대로 값이 바뀌었다

정말 순서대로 요청이 들어가고 있는지 확인해보자

const [testValue, setTestValue] = useState('');

const handleOnClick = () => {
  setTestValue(prevState => prevState + '1');
  setTestValue(prevState => prevState + '2');
  setTestValue(prevState => prevState + '3');
  setTestValue(prevState => prevState + '4');
  setTestValue(prevState => prevState + '5');
};

...
<div>{`${testValue}`}</div>
<div onClick={handleOnClick}>add 1</div>

숫자 연산으로 하면 순서가 헷갈리니 문자열 연산으로 바꾸어 보았다

순서대로 요청이 들어간다면 문자열은 “12345” 가 되어야 할 것

예상하던 대로 값이 잘 처리되었다

매우 편안하다...

결론

prevState는 비동기적으로 작동하던 setState를 나름 동기적으로 동작하게 도와주므로, 상태값이 기대하던 대로 잘 변하도록 보장해줄 수 있다

다르게 말하자면 prevState를 사용하지 않으면 내가 예상하던 대로 값이 제대로 바뀌지 않을 수 있다

이와 비슷한 문법으로 async, await가 있으며 얘네는 상태값 관련이 아니더라도 사용하여 값의 변화를 기다리고 동기적으로 작업을 수행할 수 있다

참고자료

비동기로 동작하는 react의 setState에 대하여

 

비동기로 동작하는 react의 setState에 대하여

Constructor 메서드 내에서 state를 초기화 하는 작업이 없다면, 해당 React 컴포넌트에서 생성자를 구현하지 않아도 된다. 초기화를 위해서는 아래와 같이 작성한다또는 멤버변수(클래스 필드)를 사

velog.io

What is prevState in ReactJS?

 

What is prevState in ReactJS?

I think it might be silly question to ask but trust me I am beginner to reactJS . Could someone please explain me why we use prevState in ReactjS . I tried hard to understand but failed . Here is...

stackoverflow.com

 

'ClientSide > React' 카테고리의 다른 글

데이터 불러오기, Suspense  (0) 2022.05.13
IntersectionObserver + 무한스크롤  (0) 2022.05.12
Custom Hook  (0) 2022.05.09
Too many re-renders 오류  (0) 2022.05.07
CSS Module  (0) 2022.05.04
Comments