Github
Postsreactmemoization (advanced react)

memoization (advanced react)

A set of two-state buttons that can be toggled on or off

key Point


useMemo, useCallback, React.memo를 사용할 때 유의점에 대해서 설명

Key Sentences


  • dependencies에 추가할 때, 레퍼런스를 확인해야한다.
  • useCallback을 콜백 자체를 반환하고, useMemo는 콜백을 실행한다.

컴포넌트 내부에서 선언된 함수를 그대로 useCallback이나 useMemo dependencies로 넣으면 레퍼런스는 매번 달라지기 때문에 리렌더링이 발생할 때마다 false로 계산되어서 의도하는 대로 동작하지 않음

이러한 상황에서 denpendency에 들어가는 객체를 useCallback이나 useMemo로 감싼다.

memoized props

1const Component = () => { 2 const a = useCallback(() => { 3 }, []); 4 5 return <button onClick={onClick}>click me</button>; 6};

위 예제에서 onClick을 감싸도 필요없다. Props로 리렌더링되는게 아니라 상위 컴포넌트 리렌더링이 하위 컴포넌트를 리렌더링 시키기 때문

react.memo

부모 컴포넌트의 리렌더링으로부터 하위 컴포넌트의 리렌더링이 발생하는 경우에 Props를 비교해서 변경이 없을 경우에 불필요한 리렌더링을 막을 수 있다.

memo가 안먹히는 경우

1const Child = ({ data, onChange }) => {}; 2const ChildMemo = React.memo(Child); 3 4const Component = () => { 5 // object and function declared inline 6 // will change with every re-render 7 return ( 8 <ChildMemo 9 data={{ ...some_object }} 10 onChange={() =>{...}} /> 11 ) 12}

위 예제에서 data는 새로운 객체, 함수는 인라인으로 새로운 함수(객체)가 생성되기 때문에 레퍼런스가 다름

따라서 아래와 같이 써야함

1const Child = ({ data, onChange }) => {}; 2const ChildMemo = React.memo(Child); 3 4const Component = () => { 5 const data = useMemo(() => ({ ... }), []); // some object 6 const onChange = useCallback(() => {}, []); // some callback 7 8 // data and onChange now have stable reference 9 // re-renders of ChildMemo will be prevented 10 return <ChildMemo data={data} onChange={onChange} /> 11}

신박한 예제

1const Child = () => {}; 2const ChildMemo = React.memo(Child); 3 4const Component = (props) => { 5 return <ChildMemo {...props} />; 6}; 7 8const ComponentInBetween = (props) => { 9 return <Component {...props} />; 10}; 11 12const ref = { current: } 13 14const InitialComponent = (props) => { 15 // this one will have state and will trigger re-render of Component 16 const ref = useRef({ 17 18 }) 19 20 return ( 21 <ComponentInBetween {...props} data={ref} /> 22 ); 23};

위 예제에서 InitialComponent에서 data props가 새로운 객체를 계속 내려주기 때문에 맨 하위에 ChildMemo도 메모이징이 깨진다.

react.memo hoc를 사용할 때 규칙

  1. Props로 스프레드 문법을 사용하지 않는다.
  2. 다른 컴포넌트에서 전달받은 원시타입이 아닌 데이터를 Props로 넘기지 않는다.
  3. hook으로 생성된 원시 타입이 아닌 데이터를 Props로 넘기지 않는다.

children as props

React.memo로 컴포넌트를 감싸더라도 children으로 넘기는 부모 컴포넌트가 있으면 memo로 감쌀 필요가 없다. children도 props로써 비교할 때, 레퍼런스가 다르기 때문이다.

때문에 Memo가 유용할려면 넘기는 children 컴포넌트를 useMemo로 감싸던가 해야함

useMemo는 연산이 많이 듬

  • 측정 먼저