useMemo

악음·2021년 12월 17일
2

react.js

목록 보기
9/11
post-thumbnail

면접 과제 전형중에 피드백 받은 사항이다(전형을 탈락했다)
정말 좋은 피드백이였기에 자존감을 무시하고 포스팅한다.
useEffect안에 setState하기 vs useMemo를 통해 각 로직이 변경되는 과정을 살펴보자

useEffect 안에서 setState사용하기

코드예시

만약 토탈 프라이스를 구하는 로직이 있다고 생각해보자

useEffect+setState하는 경우

... 대충 컴포넌트 내부 로직

const [totalprice,setTotalPrice]=useState(0)
// 리덕스를 이용해서 state를 가져온다
const cartSelector=useSelect(state=>state.slice.cart)

useEffect(()=>{
  let total=0
// ... 대충 cart를 가져와서 총 금액을 구하는 로직
  
  setTotalPrce(total)
},[cartSelector])

코드상엔 없지만 "증가 버튼"을 누르면 dispatch가 되고 redux의 cartState를 변하게 한다고 가정해보자.
cartSelector가 변경됨에따라 1번 리렌더링이 진행되고 useEffect에서 포착한뒤 setTotalprice()를 통해 한번더 리렌더링이 일어난다.

useMemo를 사용하는경우

useMemo를 사용하기전 memoization이 뭔지 알아보자면
참고한 싸이트
useMemo 함수에 대해서 알아보기 전에 알고리즘 시간에 자주 나오는 메모이제이션(memoization) 개념에 대해서 잠깐 짚고 넘어가겠습니다. memoization이란 기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법을 말합니다. memoization을 절적히 적용하면 중복 연산을 피할 수 있기 때문에 메모리를 조금 더 쓰더라도 애플리케이션의 성능을 최적화할 수 있습니다.

... 대충 컴포넌트 내부 로직
// 리덕스를 이용해서 state를 가져온다
const cartSelector=useSelect(state=>state.slice.cart)
const totalprice=useMemo(()=>{
  let total=0
// ... 대충 cart를 가져와서 총 금액을 구하는 로직},[cartSelector])
  return total

코드상엔 없지만 "증가 버튼"을 누르면 dispatch가 되고 redux의 cartState를 변하게 한다고 가정해보자.
그렇다면 useMemo에 뎁스에서 포착하여 로직을 재실행 할것이다.
여기서 들었던 생각은 리액트는 화면에 값이 바뀔려면 리렌더링이 일어나야한다는 것이다.
때문에 return하는순간 totalprice라는 변수를 표현하기위해 useMemo가
콤포넌트를 리렌더링 시킬것이라고 예상하게 되는데

(때문에 useEffect+setState와 다른점이 없다고 생각했다 실재로 리렌더링 2번되고있는지도 확인했고
하지만 내가 작성한 코드가 이렇게 보여지게 만들었다 이부분은 나중에 설명하겠다)

그렇지 않다.

useMemo는 렌더링 중에 값이 전달되어 화면에 표현된다.
즉 뎁스가 바뀔때 리렌더링이 시작되고 그 과정에서 1번째 파라미터로 넘겨준 함수가 실행되고
값이 변경되어 렌더링 될때 화면상에 표현된다.

즉! 렌더링이 1번만 일어나도 화면이 변한다는뜻!

useMemo 설명서
위에 링크를 통해 useMemo를 알아보자

내가 착각한부분

useMemo를 사용했음에도 리렌더링이 2번 일어난것이라고 보여지게한 코드

useSelect(state=>state.slice.cart)

위에 코드는 totalPrice콤포넌트에서 사용되어지고있고

totalPrice를 가지고있는 부모에게도 사용되어지고있었다.

정리를 해보자면

  1. cartSelect가 변하면 구독하고있는 부모 콤포넌트가 리랜더링=>자식들도 리렌더링
  2. totalPrice콤포넌트 리렌더링
  3. totalPrice콤포넌트 또한 cartSelect의 변화를 감지하여 리렌더링
  4. 때문에 useMemo를 사용했음에도 2번렌더링이 된것처럼 보여지게한것

디버깅 과정

간단히 totalPrice콤포넌트를 React.memo로 랩핑했다
이로인해 다음과같은 로직을 타게된다.

  1. cartSelect가 변하면 구독하고있는 부모 콤포넌트가 리랜더링=>자식들도 리렌더링
  2. 부모 콤포넌트의 자식들중 totalPrice 콤포넌트는 React.memo가 걸려있기때문에 렌더링을 안함
    (부모로 부터받은 props가 변한게 아니기때문)
  3. totalPrice 콤포넌트는 cartSelect의 변화를 감지하여 리렌더링
  4. 때문에 랜더링이 1번만 진행된다.

결론

정말 좋은 피드백이였고
처음 잘몰랐을땐 이해가 안되고 피드백이 잘못되었다고 생각했다
하지만 공부할수록 잘모르고있던건 나였고...

하지만 이 과정을통해 레밸업하는 느낌을 받았다.

profile
RN/react.js개발자이며 배운것들을 제가 보기위해서 정리하기 때문에 비속어 오타가 있을수있습니다.

0개의 댓글