2023. 7. 14. 07:40ㆍNext.js
state가 바뀌면 바뀐 state로 컴포넌트가 다시 만들어지는데, 불필요한 재렌더링은 성능에 악영향을 미친다.
컴포넌트가 어떻게 재생성되고, 다시 만들지 않게 하는 방법은 무엇인지 알아보자!
memoization
- 새로 만들 컴포넌트를 메모해놓고, 다음에 다시 만들어야 할 때 새로 만들지 않고 메모해 놓은 것을 가져다 쓴다고 생각하면 된다.
재렌더링 시 새로 만들어지는 것들
- 컴포넌트 안의 hook을 제외한 나머지는 전부 새롭게 다시 만들어진다.
- 부모가 새로 만들어지면 자식들도 새로 만들어진다.
렌더링이 일어나면 hook을 제외한 모든것이 새로 만들어진다.
1. let과 state
- let으로 선언한 변수는 값이 바뀌어도 화면에 반영되지 않는다.
- 반면, state가 변경되면 렌더링이 일어나고 화면에 반영된다.
- 게다가 state가 변경되면(재렌더링이 일어나면) let으로 선언한 값도 함께 초기화된다.
(state는 useState로 만든 hook이니까 새로 만들어지지 않는다.)
/* let으로 선언한 변수 */
let countLet = 0;
/* let으로 선언한 변수를 증가시키는 함수 */
const onClickCountLet = () => {
console.log("let : " + Number(countLet + 1)); // 실행될 결과
countLet += 1;
};
/* state로 선언한 변수 */
const [countState, setCountState] = useState(0);
/* state로 선언한 변수를 증가시키는 함수 */
const onClickCountState = () => {
console.log("state : " + Number(countState + 1)); // 실행될 결과
setCountState((prev) => prev + 1);
};
2. 부모 컴포넌트와 자식 컴포넌트
- 렌더링이 일어나면 부모의 하위 자식 컴포넌트도 렌더링이 일어난다.
새로 만들어지는 컴포넌트 안의 함수, 변수 등이 전부 새로 만들어지는 것이다.
3. Profiler로 확인해보기
[React Developer Tools]React Developer Tools의 Profiler: 성능 측정 도구
- React Developer Tools를 설치한다.
- 리액트 앱으로 만들어진 브라우저를 열고 개발자 도구에서 Profiler 탭으로 들어간다.
- 설정 아이콘 >
Highlight updates when components render
체크
- 렌더링이 일어나는 부분이 화면에 표시된다.
- Start profiling을 누르면 녹화를 할 수 있다.
5-1. 렌더링된 부분이 노란색으로 표시되어 나온다.
부모가 렌더링이 되면 자식도 렌더링이 된다는 것을 확인할 수 있다.
불필요한 재렌더링이 일어나지 않게 만들어보자!
Memoization
1. memo :: 자식 컴포넌트의 리렌더링 막기
- memo는 HOC의 일종으로, 부모가 렌더링되어도 자식은 렌더링 되지 않게 만들어준다.
- 자식까지 리렌더링 되는 것은 피할 수 있으면 memo를 이용해서 방지해야 한다.
- 주의할 점: memo를 쓰고 있어도 전달하고 있는 props가 변경되면 자식 컴포넌트가 리렌더링 된다.
(자식 컴포넌트에서 전달 받은 props를 사용하지 않고 있더라도 변경되면 자식 컴포넌트가 리렌더링된다.
따라서, props를 전달할 때 정말 필요한 것만 전달해야 한다.) - props가 바뀌면 바뀐다고 해서 memo를 남용하면 안된다.
메모를 한다는 것은 결국엔 어딘가에 저장된다는 것이고, 변경될 때 계속해서 체크해야 하기 때문에 남용을 하면 오히려 퍼포먼스가 더 떨어질 수 있다.
import { memo } from "react";
function ChildrenPage(props: any) {
~~ 자식 컴포넌트 ~~
}
export default memo(ChildrenPage);
2. useMemo :: 리렌더링이 일어날 때 변수의 값 유지하기
const aaa = useMemo(() => Math.random(), [countState]);
- useMemo 안에서 메모할 내용을 리턴해주면 된다.
- useEffect와 마찬가지로 dependency array가 있다.
다시 만들어줄 상황을 지정해주고 싶다면, dependency array를 활용하면 된다.
import { useMemo } from "react";
const random = Math.random();
console.log("그냥 랜덤 숫자 : " + random);
const useMemoRandom = useMemo(() => Math.random(), []);
console.log("useMemo 랜덤 숫자 : " + useMemoRandom);
👇🏻 사실, 변하지 않는 상수값이라면 useMemo를 쓰지 않고 컴포넌트 밖에 const로 선언하는 것이 편리하다..^^
그럼 언제 써?!
컴포넌트 안에서 써야 하고, 계산을 통해서 만들어지면서 리렌더 될 때 다시 계산될 필요가 없을 때 쓰면 된다.
useMemo로 함수도 저장할 수 있다.
(useMemo로 useCallback 만들기)
리턴하는 값을 함수로 넣어주면 된다.
const onClickCountState = useMemo(() => {
return () => setCountState((prev) => prev + 1);
}, []);
/* 위아래 같음 */
const onClickCountState = useMemo(
() => () => setCountState((prev) => prev + 1),
[]
);
3. useCallback :: 리렌더링이 일어날 때 함수를 다시 만들지 않게 하기
useCallback( () => { ~~함수~~ }, [] );
- 다시 만들어질 필요가 없는 함수에 사용한다.
const onClickCountState = useCallback(() => {
console.log(countState);
setCountState(countState + 1);
}, []);
useCallback의 문제점
- state까지 같이 기억해버린다..
state를 1씩 증가시키는 함수를 실행시켜도 값이 변하지 않는다.
- 따라서, useCallback 안에서 state를 직접 사용하는 것을 피해야 한다.
👇🏻/* ❌ useCallback을 잘못 사용한 예 */ const onClickCountState = useCallback(() => { console.log("state : " + Number(countState + 1)); // 증가된 결과 setCountState(countState + 1); }, []);
/* 👍🏻 옳은 예 */ const onClickCountState = useCallback(() => { setCountState((prev) => prev + 1); }, []);
useCallback을 사용하지 말아야 하는 경우
dependency array에 들어간 값이 변경되면 다시 리렌더링이 되는데,
그 값이 많아지면 언제 새로 만들어지고 만들어지지 않는지 확인이 어려워서 오히려 유지보수가 힘들어질 수 있다.
따라서, dependency array에 들어가는 값이 한 두개일 때 사용하는 것이 좋다.
관리자 사이트처럼 데이터가 많은 경우, 체크박스가 체크될 때 memoization을 하지 않으면 굉장히 버벅이게 된다!
memo만 달아줘도 성능 향상 굿임
'Next.js' 카테고리의 다른 글
Optimistic UI: 빠르게 할 수 없다면, 속여보자! ㅋㅋ (0) | 2023.07.14 |
---|---|
HOC: 먼저 실행하는 컴포넌트 만들기 (0) | 2023.07.14 |
Next.js와 브라우저 저장소 (4) | 2023.07.14 |