React 기초공부 -5

솔다·2023년 2월 17일
0

useCallback/ useMemo

이 두가지 함수에 대해서 고찰을 가져보자. 일반적으로 두 훅(Hook)을 많이 볼 수 있는데, 컴포넌트에 무언가 함수를 전달할 때마다 useCallback()함수를 호출 하는 것 같지만, 렌더링 시간에 문제를 일으킬 수 있다.

문제점

useCallback()함수를 이용하면 일반적으로 렌더링 중 함수 재생성을 방지할 수 있는 것으로 알고 있다. 정확히는 제공된 deps를 기준으로 반환된 함수 객체를 메모이제이션 하는 것 뿐이다. 즉, 동일한 deps가 제공되면 동일한 함수 객체를 반환한다. 그냥 새로운 함수를 매번 만드는 대신에, useCallback()을 사용해서 생성한 함수를 다른 컴포넌트에 넘겨준 다면 어떤 일이 발생할까.

리액트는 새로운 함수를 만들고, 함수를 실행할 때, 새로운 배열을 만들어서 실행하고, dep의 동일성을 비교하기 위한 함수와 종속성 집합을 메모리에 저장할 것이다.

함수를 단순히 props로 만들어서 전달하는 것보다 훨씬 더 많은 비용이 든다는 것을 의미한다. 물론 겉으로 봤을때는 useCallback()을 사용헀든, 사용하지 않았든, 기능적으로는 똑같이 작동했을 것이다.

Props의 참조 동일성

만약 자식 컴포넌트가 React.memo()를 사용하고 있거나, React.PureComponent로 구현되어 있는 경우, 리액트는 props가 정확하기 일치하는 한은, 부모 컴포넌트가 리렌더링 되더라도 자식 컴포넌트를 그대로 유지할 것이다. 만일props가 동일한데, 새 함수 인스턴스 또는 객체 인스턴스를 전달하게 되면, 해당 컴포넌트는 다시 렌더링 된다.

그리고, propsuseEffect()의 종속성으로 사용되는 경우에도 문제가 될 수 있다. 당연히 props가 변경 될 때 마다 이 useEffect()가 트리거 되기 때문.

useMemo()와 useCallback() 을 사용하지 말아야 할 경우

  1. host 컴포넌트에 (div,span,a,img...) 전달하는 모든항목에 대해 신경쓰지 말아야 한다. 리액트는 여기에 함수 참조가 변경되었는지 신경쓰지 않는다.(ref,mergeRefs는 제외)
  2. leaf 컴포넌트에는 쓰지 말아야 한다.
  3. useCallback, useMemo의 의존성 배열에 완전히 새로운 객체와 배열을 전달하는 경우 => 메모를 쓰는 의미가 없어진다.
  4. 전달하려는 항목이 새로운 참조인 경우. 3과 비슷하게 의미가 없다.

host 컴포넌트: 호스트 환경 (브라우저 또는 모바일)에 속하는 플랫폼 컴포넌트를 의미한다.
leaf 컴포넌트: DOM에서 다른 컴포넌트를 렌더링하지 않는 컴포넌트(html태그만 렌더링하는 컴포넌트)

반대로 useMemo와 useCallback을 사용하면 좋은 경우

  1. 하위트리에 많은 Consumer가 잆는 값을 Context Provider에 전달해야 하는 경우 useMemo를 사용하는 것이 좋다. <ProductContext.Provider value = {{id, name} >의 경우, 어떤 이유로든 해당 컴포넌트가 리렌더링 된다면 id,name이 동일하더라도 매번 새로운 참조를 만들어서 전부 리렌더링 될 것이다.
  2. 계산 비용이 많이 들고, 렌더링 이후로도 동일한 참조를 할 가능성이 높은 경우
  3. 자식 컴포넌트에서 useEffect가 반복적으로 트리거 되는 것을 막고 싶을 때 사용하자.
  4. 매우 큰 리액트 트리구조 내에서 부모가 리렌더링 되었을 때, 이에 다른 렌더링 전파를 막고 싶을 때 사용하자. 자식 컴포넌트가 React.momo, React,PureComponent일 경우, 메모이제이션 된 props를 사용하기되면 딱 필요한 부분만 리렌더링 될 것이다.

0개의 댓글