1) 컴포넌트에서 state가 변경되었을 때
2) 컴포넌트가 내려받은 props가 변경되었을 때
3) 부모 컴포넌트가 리렌더링되면 자식 컴포넌트도 모두!
최적화(Optimiztion)
리액트에서 렌더링이 자주 일어나는 것은 좋지 않으며
이를 줄이는 작업이 최적화라고 한다.
💡최적화의 대표적인 방법
React. memo) : 컴포넌트를 캐싱부모 컴포넌트의 state 변경으로 인해 props가 변경되지 않으면 memo를 통해 자식 컴포넌트의 리렌더링을 방지할 수 있다.
부모 컴포넌트가 App, 자식 컴포넌트가 Box1,Box2라 하자.
export default function App() {
console.log('App 컴포넌트 렌더링');
const [count,setCount] = 0;
const handleAdd = () => {
setCount(count+1);
})
return (
<>
<p>현재 카운트 {count}</p>
<button onClick = {handleAdd}>Add</button>
<div>
<Box1/>
<Box2/>
<div>
</>
);
}
➡️ count 값이 변경될 때마다 Box1,2 컴포넌트 모두
리렌더링이 발생한다.
React.memo를 이용하면 컴포넌트를 메모리에 저장할 수 있다.
function Box1() {
console.log('Box1 렌더링')
return <div>Box1</div>;
}
export default React.memo(Box1);
➡️ 최초 렌더링 외에 부모 컴포넌트에서 상태가 변해도 자식 컴포넌트인 Box1,Box2 컴포넌트는 리렌더링이 일어나지 않는다.
const Box1 = memo(() => {
console.log('Box1 렌더링')
return <div>Box1</div>;
}
export default Box1;
함수 선언 시 memo를 쓸 경우, 이와 같이 작성할 수 있다.
인자로 들어오는 함수 자체를 기억할 때 사용된다.
만약에 Box1 컴포넌트에서 값을 초기화하는 함수를 props를 통해 받는다고 하자.
export default function App() {
console.log('App 컴포넌트 렌더링');
const [count,setCount] = 0;
const handleAdd = () => {
setCount(count+1);
})
const resetCount = () => {
setCount(0);
})
return (
<>
<p>현재 카운트 {count}</p>
<button onClick = {handleAdd}>Add</button>
<div>
<Box1 resetCount={resetCount}/>
<Box2/>
<div>
</>
);
}
------------------------------------
function Box1({resetCount}) {
console.log('Box1 렌더링')
return <div>
Box1
<button onClick={resetCount}>리셋</button>
</div>;
}
export default React.memo(Box1);
➡️ 따라서 리셋 함수를 별도로 메모리에 저장하면 된다!
useCallback도 useEffect와 같이 의존성 배열을 넣는다.
const resetCount = useCallback(() => {
setCount(0);
},[])
🧐 리셋 버튼을 누르는 시점에서 count를 출력하면 값이
어떻게 나올까?
일단 리셋하는 함수에서 출력해보자.
const resetCount = useCallback(() => {
console.log(`${count}에서 0으로 변함`);
setCount(0);
},[])
놀랍게도 '0에서 0으로 변함'이 출력된다.
useCallback을 통해 카운트를 설정한 값(setCount(0))이 스냅샷으로 저장되어 있기 때문에 0으로 나온다.
리셋을 누른 시점에서의 count를 출력하고 싶으면
의존성 배열에 count 변수를 추가하면 된다.
const resetCount = useCallback(() => {
console.log(`${count}에서 0으로 변함`);
setCount(0);
},[count])
카운트 값이 변경될 때마다 useCallback이 다시 저장되기 때문에 해당 시점에서의 count를 제대로 출력하지만
Box1 컴포넌트도 리렌더링이 일어난다.
함수가 리턴하는 값 자체를 기억할 때 사용된다.
의존성 배열 역시 존재한다. 주로 무거운 일을 할 때 사용된다.
export default Counter() {
const [count,setCount] = useState(0);
const handleAdd = () => {
setCount(count+1);
}
const calculate = () => {
for(let i =0; i < 1000000;i++){
console.log('☺️');
}
return 100;
}
const value = calculate();
return (
<>
<p>{count}</p>
<button onClick = {handleAdd}>+</button>
</>
);
}
➡️ 계산 작업으로 반환한 값을 useMemo를 통해 메모리에 저장한다.
const value = useMomo(() => calculate(),[]);
👉아까와 다르게 바로바로 카운트가 증가되는 것을 볼 수 있다.