무거운 컴포넌트 만들기
무거운 작업을 하는 컴포넌트를 흉내내기 위해서 다음과 같은 컴포넌트를 정의해보자.
function Child() {
let start = new Date().getTime();
for (; new Date().getTime() - start < 2000; ) {}
return <div>오래걸리는 자식</div>;
}
자. 2초 뒤에 렌더링되는 느~리고 무거~운 컴포넌트를 만들었다.
그리고 리렌더링 시키기 위해 상위컴포넌트에서 state를 하나 정의해보자.
function Component() {
const [count, setcount] = useState(0);
return (
<div>
<button onClick={() => setcount((c) => c + 1)}>자식 상태 변경</button>
<p>자식상태: {count}</p>
<Child />
</div>
);
}
버튼을 누를 때마다 Component는 리렌더링 되는데 무거운 컴포넌트인 Child 때문에 렌더링이 완료되는데까지 2초 이상 걸릴 것이다!
직접 확인해보자.
여기서 Child 컴포넌트가 Component가 리렌더링 될 때 같이 리렌더링될 필요가 있을까?
count state와 어떠한 의존성도 갖지 않으므로 같이 리렌더링 될 필요가 없어보인다.
이제 Child 컴포넌트의 렌더링을 최적화해보자.
이 게시글에서는 두가지 방법을 소개할 것이다.
1. React.memo
function Child() {
let start = new Date().getTime();
for (; new Date().getTime() - start < 2000; ) {}
return <div>오래걸리는 자식</div>;
}
export default React.memo(Child);
React.memo는 컴포넌트에 메모이제이션을 적용할 수 있도록 해주는 최적화 전용 고차 컴포넌트이다.
React.memo로 함수컴포넌트를 래핑해주면 해당 컴포넌트에 대해 이전에 렌더했던 결과값을 기억하고 있는다.
그리고 이후에 Child의 리렌더링이 요구된다면 props가 바뀌었는지만 비교한다.
props가 바뀌지 않았다면 기억하고 있던 이전값을 사용해서 렌더링한다.
이렇기 때문에 2초가 걸렸던 Child의 리렌더링을 최적화 할 수 있게 된다.
처음에 렌더링했던 <div>오래걸리는 자식</div> 라는 결과물을 기억하고 있기 때문이다.
2. render with props
두번째 방법은 상위 컴포넌트에서 Child를 렌더한 결과 값을 Component에게 props로 전달하는 방법이다.
이 방식이 왜 리렌더링을 최적화하는지 알아보자.
function App() {
return (
<div>
<Component child={<Child />} />
</div>
);
}
우선 이렇게 상위 컴포넌트에서 Child 컴포넌트를 Component의 props로 전달하도록 코드를 변경해보자.
그리고 Component를 다음과 같이 바꿔보자.
function Component({ child }) {
const [count, setcount] = useState(0);
return (
<div>
<button onClick={() => setcount((c) => c + 1)}>자식 상태 변경</button>
<p>자식상태: {count}</p>
{child}
</div>
);
}
왜 될까?
이유는 React Element의 구조에 있다.
부모 컴포넌트에서 Child 컴포넌트 호출 결과를 Component의 props로 전달하고 있다.
리렌더링은 Component의 setcount에 의해 발생한다.
하지만 Component가 리렌더링될 때 이미 props로 전달받은 Child는 아무런 변화가 없다.
React는 props의 변경유무에 따라 리렌더링을 수행하기에 Element를 한번 생성한 뒤 이를 재사용하는 메커니즘이다.
React.memo 없이도 props와 JSX의 특징을 이용해 간단하게 리렌더링을 최적화 할 수 있었다.
끝내며
비용이 비싼 리렌더링을 최적화하는 방법을 간단하게 알아보았다.
성능적으로 개선이 필요할 때 적용해보면 좋을 것 같다!
'유연해지기 > React.js' 카테고리의 다른 글
React 18 의 새 기능 자동 배칭(Automatic Batching)은 무엇일까? (7) | 2022.04.10 |
---|---|
React에서 Intersection Observer로 이미지 Lazyloading 구현하기 with 콜백 ref (4) | 2022.03.30 |
리액트에서 이미지 미리보기 만들어보기 (React Image Preview) (1) | 2021.11.14 |
간단한 리액트 커스텀 훅 만들어보기. (React custom hook) (0) | 2021.11.04 |
리액트 절대경로 설정 및 모듈/경로 별명 짓기 with CRA (absolute path, path alias) (0) | 2021.10.21 |