React에서는 컴포넌트가 구독하고 있는 상태 값이나 부모로부터 받은 Props가 변한다거나 부모 컴포넌트가 리렌더링되면 컴포넌트가 리렌더링이 된다.
React는 수 많은 컴포넌트들이 부모-자식 관계로 얽혀있는데 이 부분에서 불필요한 렌더링이 일어난다면 이를 방지해줘야한다.
memo는 컴포넌트를 렌더링하고 결과를 메모이징한다. 그리고 다음 렌더링이 일어날 때 props가 같다면 React는 메모이징 된 내용을 재사용하게 된다.
import { memo } from "react";
const User({ user }) {
return (
<div className="item">
<div>이름: {user.name}</div>
<div>나이: {user.age}</div>
</div>
);
}
export default memo(User);
위 소스코드를 보면 memo로 User컴포넌트를 감싸서 사용을 하고있다. user props가 변하지 않는다면 메모이징된 결과를 재사용하게된다.
React에서 CPU 소모가 심한 함수들을 캐싱하기 위해 사용됨. 컴포넌트에서 함수가 값을 리턴할 때 값의 변화가 없음에도 리렌더링되면서 다시 함수가 호출되면 많은 리소스 낭비가 일어남 따라서 리소스를 많이 사용하는 함수는 useMemo를 이용해 의존값들이 변하지 않으면 다시 호출하지않고 캐싱된 값을 사용한다.
const MyComponent({ x, y }) {
const z = useMemo(() => compute(x, y), [x, y]);
return <div>{z}</div>;
}
위 소스코드를 보면 의존 값으로 x, y를 넣어줬다. 즉 x, y의 값이 변경되는게 아니라면 React는 이전에 함수를 호출하여서 다시 계산을 하지 않고 이전에 기억해뒀던 z값을 재사용하게된다.
즉 간단한 함수보다는 복잡한 연산을 하는 함수에서 다시 연산을 하지 않고 이전의 return값을 기억해서 사용하므로 성능상에서 많은 이점을 볼 수 있다.
useMemo는 리턴되는 값을 memoize하는 경우, useCallback은 함수 선언을 memoize한다. 리렌더링이 이루어지면 기존 함수 또한 새로 생겨나기때문에 의존 값이 변하지 않으면 기존 함수를 캐싱하여 이용한다.
const onChange = useCallback(
e => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value
});
},
[inputs]
);
useCallback, useMemo, React.memo 모두 성능상의 이점을 줄 수 있지만 간단한 함수, 복잡하지 않은 연산들에도 무조건적으로 사용하게 되면 오히려 최적화에 대한 비용이 더욱 커지게 되므로 성능이 더욱 안좋아 질 수 있다.
즉 언제 어디서 써야하는지 판단을하여 적재적소에 사용해야 더욱 빛을 볼 수 있다.