-
useCallBack hook과 setState 실행 문제.문제 해결 기록 2022. 9. 8. 01:36
프로젝트를 수행하면서 겪었던 문제입니다.
import { useState, useCallback } from "react"; import Child from "./Child"; function App() { const [count, setCount] = useState(0); const callSetCount = useCallback(() => { setCount(count + 1); console.log('callSetCount has just been called.'); }, []); return ( <div className="App"> <h1>Parent</h1> <Child callSetCount={callSetCount}/> <p>{count}</p> <button onClick={callSetCount}>callSetCount in Parent</button> </div> ); } export default App;
일단 현재 컴포넌트에서는 자식 컴포넌트인 Child에 callSetCount 함수를 props로 전송하고있습니다.
하지만 이 Child 컴포넌트 안에는 굉장히 복잡하고 어려운 렌더링 로직이 있어 부모 컴포넌트가 재렌더링될 때마다 함께 렌더링을 수행하는게 부담스러운 상황입니다.
이 상황에서 저는 useCallBack hook을 사용해서 부모 컴포넌트가 재렌더링될 때, 현재의 callSetCount의 주소값 변경을 방지해 Child 컴포넌트의 재렌더링을 막았습니다.
여기까지는 문제가 없었습니다.
하지만 callSetCount 함수를 호출하는 버튼을 두 번 눌렀을 때부터 callSetCount 함수 내부에서 실행되는 setCount 함수가 실행되지 않았습니다. 그러나 바로 밑의 콘솔 출력 코드는 온전히 수행되고 있습니다.
즉, callSetCount 함수는 온전히 호출되는 상황이나 setCount 함수의 실행이 멈춰, count 상태변수가 1부터 변경되지않고 있습니다.
물론 useCallBack hook의 두 번째 인자인 dependency list 배열에 count 상태변수를 넣어주면 setCount 함수가 작동하지만, 이렇게되면 callSetCount 함수의 주소값이 변경되어 Child 컴포넌트의 재렌더링을 방지하지 못하게됩니다.
일단, 문제를 파악하기위해 useCallBack hook의 콜백 함수 내부에 로그함수를 넣어 count의 값을 출력해 보았습니다.
대충 문제의 윤곽이 보입니다.
callSetCount 함수를 실행하면 브라우저에는 count의 값이 딱 0에서 1까지는 렌더링이 된다고 위에서 적어놨습니다. 재렌더링으로 브라우저에 변경 값이 적용되었다면, 컴포넌트 내부적으로 count라는 상태 변수는 확실하게 1까지 변화를 한 것입니다.
하지만 hook 내부의 콜백함수가 count의 상태를 계속 0이라고 인지하여 setCount함수에 결과값이 1인 count + 1를 인자로 넣으니 state가 변화하지 않고 그에 따른 재렌더링도 발생하지 않았던 것입니다.
그렇다면, callSetCount 함수에 매개변수로 변경된 count의 값을 전달하든 뭐든 setCount에 업데이트 된 count 값을 넣을 방법이 있을 것이라고 생각했습니다.
const callSetCount = useCallback(() => { setCount(count => { console.log('count: ' + count); return count + 1; }); console.log('callSetCount has just been called.'); }, []);
삽질을 거듭한 후, 제가 해결한 방식입니다.
setCount 함수의 인자로 단순히 변수가 아닌 콜백 함수를 넣어 state 변수를 변경했습니다.
이러면 state 변경 함수인 setCount도 잘 동작하고, Child 컴포넌트도 재렌더링을 방지할 수 있습니다. (React.memo 적용 가정 하.)
'문제 해결 기록' 카테고리의 다른 글
A non-serializable value was detected in the state 에러 해결. (0) 2022.10.24 StompJs에서 이미지 이진 데이터 전송하기, 문제 해결 (0) 2022.09.06 React의 자식 컴포넌트 재렌더링 방지하는 법. shouldComponentUpdate 함수 사용. (0) 2022.09.03 Cannot find module './*.module.css' or its corresponding type declarations. 에러 핸들링 (0) 2022.09.01