useCallback ? 콜백함수 그 자체를 메모이제이션
값이 3일때 callSomeF 버튼을 누르고, 다시 input의 number을 2번 클릭해서 5로 바꿨는데, 왜
useEffect(() => {
console.log('someF 실행가즈앙');
}, [someF]);
이 함수가 실행됐을까? someF는 그대로인데..
왜냐면?
number의 state가 바뀌면서, App컴포넌트가 다시 렌더링되는데, 이때
const someF = () => {
console.log(`someF:${number}`);
return;
};
이 변수도 초기화가된다. 이 변수는 함수이므로, 참조형 데이터. 즉, 메모리주소가 저장된건데,
이 변수가 초기화될때 똑같은함수이지만 새로운 메모리공간에 저장이되므로 메모리주소가 변한다. 바뀐메모리주소가 someF에 할당이되는것.
리액트입장에서는 someF의 주소가바뀐거니 변수의값(메모리주소)이 바뀐거나 다름없는것! 그래서
useEffect(() => {
console.log('someF 실행가즈앙');
}, [someF]);
요게실행된다.
이를 막으려면, useCallback~
const someF = useCallback(() => {
console.log(`someF:${number}`);
}, []);
만약 의존성배열에 빈 배열을 넣게되면,
number가 6일때 버튼을 눌러도
콘솔에는 0이 출력된다.
처음렌더링될때, number가0일때 메모이제이션이됐기때문에!
제대로 동작하게하려면, 의존성배열에 number를 넣어주자
const someF = useCallback(() => {
console.log(`someF:${number}`);
}, [number]);
이렇게 해주면 정상작동한다!
useEffect(() => {
console.log('someF 실행가즈앙');
}, [someF]);
number가 바뀌면 아까처럼 얘 또한 작동해서 콘솔로그 'someF 실행가즈앙'가 찍힌다. 왜냐면, number가바뀌면 someF가 바뀌니까
const [toggle, setToggle] = useState(true);
<button onClick={() => setToggle(!toggle)}>{toggle.toString()}</button>
버튼을 추가해서 useCallback 적용 전후를 비교해보자.
const someF = () => {
console.log(`someF:${number}`);
return;
};
useEffect(() => {
console.log('someF 실행가즈앙');
}, [someF]);
토글버튼을 누르면, toggle의 상태가변하면서 someF가 초기화되면서 useEffect내 함수가 실행된다.
const someF = useCallback(() => {
console.log(`someF:${number}`);
return;
}, [number]);
useEffect(() => {
console.log('someF 실행가즈앙');
}, [someF]);
토글버튼을 누르면, toggle의 상태가변하는데 App컴포넌트가 렌더링될때 someF는 메모이제이션으로인해 useEffect내 함수가 실행되지않는다
import Box from './Box.js';
export default function App() {
const [size, setSizes] = useState(100);
const [isDark, setIsDark] = useState(false);
const BoxStyle = () => {
return {
backgroundColor: 'pink',
width: `${size}px`,
height: `${size}px`,
};
};
return (
<div
style={{
backgroundColor: isDark ? 'black' : 'yellow',
}}
>
<input
type="number"
value={size}
onChange={(e) => setSizes(e.target.value)}
/>
<hr />
<Box BoxStyle={BoxStyle} />
<button onClick={() => setIsDark(!isDark)}>change</button>
</div>
);
}
const Box = ({ BoxStyle }) => {
const [style, setStyle] = useState({});
useEffect(() => {
console.log('박스 사이즈 조절~');
setStyle(BoxStyle());
}, [BoxStyle]);
return <div style={style}></div>;
};
export default Box;
change를 누르면
useEffect(() => {
console.log('박스 사이즈 조절~');
setStyle(BoxStyle());
}, [BoxStyle]);
이 코드가 실행이된다. isDark의 state가 변하면서 App컴포넌트가 재렌더링되면서,
const BoxStyle = () => {
return {
backgroundColor: 'pink',
width: `${size}px`,
height: `${size}px`,
};
};
이 BoxStyle함수가 다시 초기화되는데, 함수객체이기때문에 다른 메모리주소값이 저장되기때문! 그래서 리액트는 BoxStyle이 변했으니까, useEffect를 실행하는거다. 나는 isDark의 state를 변화시켰는데 isDark와 상관없는 함수가 실행되고있으니까 이를 막으려면 useCallback~
const BoxStyle = useCallback(() => {
return {
backgroundColor: 'pink',
width: `${size}px`,
height: `${size}px`,
};
}, [size]);
이제 isDark의 state가 변화가 되어도, useEffect는 일어나지않는다.
모든 출처: 별코딩 유튜브