컴포넌트를 캐싱
부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두 리-렌더링 된다.
1번 컴포넌트가 리렌더링 된 경우 2~7번 모두 리렌더링 된다.
2번 컴포넌트가 리렌더링 된 경우 4~7번 모두 리렌더링 된다.
❌ 문제 : 자녀 컴포넌트의 입장에서 바뀐게 없을 때 리렌더링 되는 것이 비효율적일 수 있다.
💡 해결 : React.memo 를 사용한다.
예제
// 상위 컴포넌트
import React, { useState } from "react";
import Box1 from "./Box1";
import Box2 from "./Box2";
import Box3 from "./Box3";
export default function Test() {
console.log("테스트가 렌더링 되었습니다.");
const [count, setCount] = useState(0);
return (
<div>
<h3>카운트 예제</h3>
<p>현재 카운트 : {count}</p>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<div style={{ display: "flex" }}>
<Box1 />
<Box2 />
<Box3 />
</div>
</div>
);
}
// 하위 컴포넌트
function Box1() {
console.log("박스 1이 렌더링 되었습니다.");
return <div style={boxStyle}>Box1</div>;
}
export default Box1;
// 하위 컴포넌트
function Box1() {
console.log("박스 1이 렌더링 되었습니다.");
return <div style={boxStyle}>Box1</div>;
}
export default React.memo(Box1);
// 상위 컴포넌트
export default function Test() {
console.log("테스트가 렌더링 되었습니다.");
const reset = () => setCount(0);
const [count, setCount] = useState(0);
return (
<div>
<div style={{ display: "flex" }}>
<Box1 />
<Box2 reset={reset} />
<Box3 />
</div>
</div>
);
}
// 하위 컴포넌트
function Box2({ reset }) {
console.log("박스 2이 렌더링 되었습니다.");
return (
<div style={boxStyle}>
<button onClick={reset}>초기화</button>
</div>
);
}
export default React.memo(Box2);
컴포넌트에서 State가 바뀌었는가? No / 부모 컴포넌트가 리-렌더링 된 경우 자식 컴포넌트는 모두 No => React.memo
로 막아줌
이 경우 Props가 변경되서 리렌더링 된 것이다.
function
은 객체의 한 종류이다.object
를 저장하는 방법 => object
를 저장하는 것이 아니라 주소를 저장한다. 따라서 a,b는 주소값이 서로 다르기 때문에 다른 object
이다.reset
라는 함수가 새로운 메모리에 다시 할당된다.Props
를 받을 때 주소값이 다르기 때문에 다른 Props
라고 생각, 즉 Props
가 바뀌었다고 생각한다.예제
Props
로 내려주는 함수에 useCallback를 쓴 결과 하위 컴포넌트는 리렌더링 되지 않는다.export default function Test() {
console.log("테스트가 렌더링 되었습니다.");
const reset = useCallback(() => setCount(0), []);
const [count, setCount] = useState(0);
return (
<div>
<div style={{ display: "flex" }}>
<Box1 />
<Box2 reset={reset} />
<Box3 />
</div>
</div>
);
}
${count}
는 최초 기억하는 값인 0이 뜬다. const reset = useCallback(() => {
console.log(`Count가 ${count}에서 0으로 변경되었습니다.`);
setCount(0);
}, []);
count
를 넣어 해결하였다. const reset = useCallback(() => {
console.log(`Count가 ${count}에서 0으로 변경되었습니다.`);
setCount(0);
}, [count]);
값을 캐싱 : 객체나 배열이나 함수가 이에 해당
동일한 값을 반환하는 함수를 계속 호출하는 등 불필요한 렌더링을 할 때 사용한다.
맨 처음 해당 값을 반환할 때 그 값을 특별한 곳(메모리)에 저장
=> 필요할 때마다 다시 함수를 호출하는 것이 아니라 이미 저장한 값을 꺼내와서 쓴다.
예시
function Box3() {
const [count, setCount] = useState(0);
const heavyWork = () => {
for (let i = 0; i < 500000000; i++) {
//
}
return 100;
};
// const value = heavyWork() => useMemo를 사용하지 않을 때
const value = useMemo(() => heavyWork(), []); => useMemo를 사용할 때
return (
<div style={boxStyle}>
{value}
<br />
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
<br />
{count}
</div>
);
}
export default React.memo(Box3);
무조건 쓰면 좋으냐 ? No => 가벼운 하위 컴포넌트에 전부 다 써주면 캐시를 어마어마하게 잡아 먹기 때문에 오히려 안쓰는게 최적화에 더 효율적이다.
props에서 변화가 너무 많이 일어나면 오히려 안쓰는 것이 효율적이다.
번외 : div태그만 쓰면 seo에 안좋다. => 검색할 때 태그도 다 반영하기 때문에