-
[React] React.memo vs useMemo vs useCallbackReact 2022. 10. 22. 14:29
1. 사용 이유
결론은, React.memo, useMemo와 useCallback은 react의 성능을 향상(불필요한 렌더링 또는 변수, 함수 호출 방지)이 목적입니다.
* React.memo는 HOC이고, useMemo와 useCallback은 hook입니다.
컴포넌트가 렌더링이 되면, 선언된 함수형 컴포넌트들 안에 있던 변수, 함수도 다시 정의되고, 사용됩니다.
또한, 컴포넌트는 자신의 state나 부모 컴포넌트로 부터 받은 props가 변경, 혹은 부모 컴포넌트가 리렌더링될 때마다 리렌더링됩니다.
그래서 재렌더링의 작업이 많아질 경우, 불필요한 함수 혹은 변수가 호출될 수 있습니다.
→ 특정 컴포넌트, 함수와 변수(값)을 메모이제이션하게 만들고 싶을 경우, React.memo, useMemo와 useCallback을 이용하면 됩니다.
참조 : [리액트의 리렌더링 조건]
자신의 state 가 변경될 때,
부모 컴포넌트로 부터 받은 prop가 변경될때,
부모 컴포넌트가 리렌더링 될때)2. React.memo
const MyComponent = React.memo(function MyComponent(props) { /* props를 사용하여 렌더링 */ });
React.memo는 고차 컴포넌트(Higher Order Component)입니다.
컴포넌트가 동일한 props로 동일한 결과를 렌더링해낸다면, React.memo를 호출하고 결과를 메모이징(Memoizing)하도록 래핑하여 경우에 따라 성능 향상을 누릴 수 있습니다. 즉, React는 컴포넌트를 렌더링하지 않고 마지막으로 렌더링된 결과를 재사용합니다.
React.memo는 props 변화에만 영향을 줍니다. React.memo로 감싸진 함수 컴포넌트 구현에 [useState](<https://ko.reactjs.org/docs/hooks-state.html>), [useReducer](<https://ko.reactjs.org/docs/hooks-reference.html#usereducer>) 또는 [useContext](<https://ko.reactjs.org/docs/hooks-reference.html#usecontext>) 훅을 사용한다면, 여전히 state나 context가 변할 때 다시 렌더링됩니다.
출처: react 공식문서
react 공식문서를 보면 설명되었듯이, React.memo로 감싸진 컴포넌트를 렌더할 때, 그 결과를 메모이제이션합니다. 그 후 리렌더링이 일어날 때, props과 같으면, 메모리에 저장된 값을 재사용합니다. 그래서 컴퍼넌트가 같은 props로 자주 렌더링되거나, 무겁고 비용이 큰 연산이 있는 경우, React.memo()로 컴퍼넌트를 래핑할 필요가 있습니다.
* [주의]
props에 object가 저장이 될 경우(주소 값이 저장된 경우: 함수, object, array 등),
동일한 props라고 보일지도 부모가 렌더링 될때마다 주소값이 달라질 것이므로 props가 다르다고 인식합니다.
그러므로 이를 해결하기 위해 props에 해당하는 값, 함수에 대해 아래에 쓰이는 useMemo 혹은 useCallback을 사용해야 합니다.
3.useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); //첫번째 인자 : 콜백함수 //두번째 인자 : 의존성 배열
메모이제이션된 값을 반환합니다.
“생성(create)” 함수와 그것의 의존성 값의 배열을 전달하세요. useMemo는 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산 할 것입니다. 이 최적화는 모든 렌더링 시의 고비용 계산을 방지하게 해 줍니다.
useMemo로 전달된 함수는 렌더링 중에 실행된다는 것을 기억하세요. 통상적으로 렌더링 중에는 하지 않는 것을 이 함수 내에서 하지 마세요. 예를 들어, 사이드 이펙트(side effects)는 useEffect에서 하는 일이지 useMemo에서 하는 일이 아닙니다.
출처: react 공식문서
useMemo는 다음과 같은 동작 순서를 가집니다.
렌더링 → 컴포넌트 함수 호출 → memorized function 재사용
useMemo는 처음에 계산된 결과값을 메모리에 저장해서, 컴포넌트가 계속 렌더링이 되어도 저장된 값만 호출할 수 있게 해줍니다. 즉, 불필요하게 함수를 호출하지 않으므로 성능을 높일 수 있는 것입니다. 그래서, useMemo는 함수의 연산량이 많을때 이전 결과값을 재사용하기 위해 쓰입니다.
* [주의]
useMemo 값을 메모리에 저장하는 만큼, 너무 많이 남발하면 메모리 성능에 악화를 줄 수 있습니다.
또한, useMemo는 렌더링 도중 실행하므로, 생성과 관련된 작업을 할 때 사용하기(ex- 사이드 이펙트 관련 일에는 어울리지 않는다.)
4. useCallback
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
메모이제이션된 콜백을 반환합니다.
인라인 콜백과 그것의 의존성 값의 배열을 전달하세요. useCallback은 콜백의 메모이제이션된 버전을 반환할 것입니다. 그 메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경됩니다. 이것은, 불필요한 렌더링을 방지하기 위해 (예로 shouldComponentUpdate를 사용하여) 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용합니다.
useCallback(fn, deps)은 useMemo(() => fn, deps)와 같습니다.
출처: react 공식문서
useMemo는 값(value)를 반환하는 반면, useCallback은 함수(function)을 반환합니다.
그래서, useCallback은 함수가 재생성 되는것을 방지하기 위해 쓰입니다.
참고문서
https://ui.toast.com/weekly-pick/ko_20190731
https://leehwarang.github.io/2020/05/02/useMemo&useCallback.html
'React' 카테고리의 다른 글
[React] React 컴포넌트 설계 패턴 (0) 2023.04.15 [React] JSX.Element vs ReactNode vs ReactElement (1) 2022.10.08 [React] HOC(high order component)의 개념과 사용법 (0) 2022.08.30