이 두가지 함수에 대해서 고찰을 가져보자. 일반적으로 두 훅(Hook)을 많이 볼 수 있는데, 컴포넌트에 무언가 함수를 전달할 때마다 useCallback()
함수를 호출 하는 것 같지만, 렌더링 시간에 문제를 일으킬 수 있다.
useCallback()
함수를 이용하면 일반적으로 렌더링 중 함수 재생성을 방지할 수 있는 것으로 알고 있다. 정확히는 제공된 deps
를 기준으로 반환된 함수 객체를 메모이제이션 하는 것 뿐이다. 즉, 동일한 deps가 제공되면 동일한 함수 객체를 반환한다. 그냥 새로운 함수를 매번 만드는 대신에, useCallback()
을 사용해서 생성한 함수를 다른 컴포넌트에 넘겨준 다면 어떤 일이 발생할까.
리액트는 새로운 함수를 만들고, 함수를 실행할 때, 새로운 배열을 만들어서 실행하고, dep의 동일성을 비교하기 위한 함수와 종속성 집합을 메모리에 저장할 것이다.
함수를 단순히 props로 만들어서 전달하는 것보다 훨씬 더 많은 비용이 든다는 것을 의미한다. 물론 겉으로 봤을때는 useCallback()
을 사용헀든, 사용하지 않았든, 기능적으로는 똑같이 작동했을 것이다.
만약 자식 컴포넌트가 React.memo()
를 사용하고 있거나, React.PureComponent
로 구현되어 있는 경우, 리액트는 props가 정확하기 일치하는 한은, 부모 컴포넌트가 리렌더링 되더라도 자식 컴포넌트를 그대로 유지할 것이다. 만일props
가 동일한데, 새 함수 인스턴스 또는 객체 인스턴스를 전달하게 되면, 해당 컴포넌트는 다시 렌더링 된다.
그리고, props
가 useEffect()
의 종속성으로 사용되는 경우에도 문제가 될 수 있다. 당연히 props
가 변경 될 때 마다 이 useEffect()
가 트리거 되기 때문.
div
,span
,a
,img
...) 전달하는 모든항목에 대해 신경쓰지 말아야 한다. 리액트는 여기에 함수 참조가 변경되었는지 신경쓰지 않는다.(ref
,mergeRefs
는 제외)leaf
컴포넌트에는 쓰지 말아야 한다.useCallback
, useMemo
의 의존성 배열에 완전히 새로운 객체와 배열을 전달하는 경우 => 메모를 쓰는 의미가 없어진다.host 컴포넌트: 호스트 환경 (브라우저 또는 모바일)에 속하는 플랫폼 컴포넌트를 의미한다.
leaf 컴포넌트: DOM에서 다른 컴포넌트를 렌더링하지 않는 컴포넌트(html태그만 렌더링하는 컴포넌트)
useMemo
를 사용하는 것이 좋다. <ProductContext.Provider value = {{id, name} >
의 경우, 어떤 이유로든 해당 컴포넌트가 리렌더링 된다면 id
,name
이 동일하더라도 매번 새로운 참조를 만들어서 전부 리렌더링 될 것이다.useEffect
가 반복적으로 트리거 되는 것을 막고 싶을 때 사용하자.React.momo
, React,PureComponent
일 경우, 메모이제이션 된 props를 사용하기되면 딱 필요한 부분만 리렌더링 될 것이다.