만족

[React] Hook 에서 prev state 값 사용하기 본문

[React] Hook 에서 prev state 값 사용하기

FrontEnd/React Satisfaction 2021. 7. 21. 02:04

class component에서의 prev state

componentDidUpdate(prevProps, prevState, snapshot)

class component에서는 componentDidUpdate 라이프사이클에서 이전 상태값들을 사용할 수 있었다.

 

Function component에서의 prev state

 

그러나 hook에서는 위와 같은 라이프사이클이 존재하지 않는다.

 

따라서 hook을 커스텀해서 prev state를 담을 수 있는 새로운 state를 생성해 활용한다.

 

usePrevState.js

import { useEffect, useRef } from "react";

export function usePrevState(state) {
  const ref = useRef(state);
  useEffect(() => {
    ref.current = state;
  }, [state]);
  return ref.current;
}

이 코드가 의미하는 것은 무엇일까?

 

useRef?

useRef를 이용해 만든 값은 컴포넌트가 언마운트될 때 까지 값을 홀드한다.

 

값을 변경하거나, 사용할 때 ref.current 값을 이용한다.

 

state와 ref의 다른 점은, state의 변경은 렌더링을 발생시키지만,

ref의 변경은 그렇지 않다는 점이다.

 

렌더링이 발생해도 이전에 저장한 값이 유지된다는 점은 동일하다.

 

어떤 state의 이전 값을 저장하기 위해 사용하므로,

리렌더링을 발생시키지 않으면서 값을 유지하는 useRef를 사용하는 것이 합리적이다.

 

useEffect?

  useEffect(() => {
    ref.current = state;
  }, [state]);

이 부분에서는 state가 변경된 이후, ref.current= state를 하고 있다.

 

즉, state가 변경된 직후의 ref.current에는 아직 변경되지 않은

이전의 state가 들어가 있다는 말이다.

 

그런데 useRef로 만든 데이터의 변경은 리렌더링을 발생시키지 않는다.

 

따라서 컴포넌트에서 ref.current의 변화는 리렌더링을 발생시키지 않기 때문에

()=>{ref.current= state}가 적용되기 전의 ref.current를 출력하게 된다.

 

시간이 조금 지난 이후에는 ref.current 역시 state와 동일하게 변경되지만,

컴포넌트(usePrevState를 사용하는 컴포넌트)가 렌더링될 때는 currentState와 비교할 때는 변경되기 전 상태라 prevState 값을 갖고 있게 된다.

 

1. 컴포넌트에서 state의 업데이트

2-1. usePrevState로 받은 ref.current값은 업데이트되지 않은 상태

2-2. 컴포넌트 리렌더링

3-1. usePrevState의 ref.current의 값이 state와 동일하게 변경됨

3-2. 컴포넌트 리렌더링 발생하지 않음

 

사용하기

export const Counter = () => {
  const [count, setCount] = useState(0);
  const prevCount = usePrevState(count);

  return (
    <div>
      <p>count: {count}</p>
      <p>prevCount: {prevCount}</p>
      <span
        onClick={() => {
          setCount(count + 1);
        }}
      >
        increase
      </span>
    </div>
  );
};

이 코드로 실험해보자.

 

정상적으로 작동한다.

 

작동 시나리오를 Counter에 맞춰 다시 정리해보자.

 

1. 컴포넌트에서 count의 업데이트

2-1. usePrevState로 받은 ref.current값(prevCount)은 업데이트되지 않은 상태

2-2. 컴포넌트 리렌더링

3-1. usePrevState의 ref.current의 값(prevCount)이 count와 동일하게 변경됨

3-2. 컴포넌트 리렌더링 발생하지 않음



Comments