useCallback은 함수를 메모이제이션해서 콜백함수를 반환해 의존성 배열에 있는 요소가 변경되었을 때 실행된다.
예를 들어 다음과 같은 코드가 있다고 가정해보자. (Demo 컴포넌트는 신경쓰지 않아도 된다)
function App() {
const [showParagraph, setShowParagraph] = useState(false);
const [allowToggle, setAllowToggle] = useState(false);
const toggleParagraphHandler = useCallback(() => {
if (allowToggle) {
setShowParagraph((prev) => !prev);
}
}, [allowToggle]);
const allowToggleHandler = () => {
setAllowToggle(true);
};
return (
<div className='app'>
<Demo show={showParagraph} />
<Button onClick={allowToggleHandler}>토글 허용</Button>
<Button onClick={toggleParagraphHandler}>토글 버튼</Button>
</div>
);
}
export default App;
toggleParagraphHandler 함수는 allowToggle 이라는 state를 포함하고 있다.
여기서 드는 의문은 useCallback은 함수를 반환한다고 했는데 allowToggle를 참조하고 있으니 당연히 바뀐 allowToggle의 값도 알아서 가져와야하지 않나? 라는 생각이 든다. 즉, 의존성 배열이 왜 필요한가? 라는 의문으로 이어진다.
의존성 배열이 있지 없어도 해당 변화된 상태를 가져와서 호출을 할 수 있어야 하지 않나 라는 의문이 든다는 것이다.
이 궁금증을 해결하기 위해서는 리액트보단 자바스크립트의 영역으로 넘어간다.
자바스크립트의 클로저 개념을 생각해야한다.
클로저 함수는 내부 함수로서, 자신이 선언된 외부 함수의 변수에 접근할 수 있다. 이러한 접근은 외부 함수가 이미 실행을 마쳤거나, 외부 함수가 아직 실행 중이더라도 클로저 함수가 호출될 때 가능하다. 클로저 함수는 자신이 선언된 어휘적 환경을 기억하고 있으므로 이전에 선언된 변수에 접근할 수 있다.
function outerFunction() {
var outerVariable = 'I am outside!';
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
var closure = outerFunction();
closure(); // 출력: "I am outside!"
innerFunction은 outerFunction에 있는 outerVariable에 접근할 수 있고 이는 클로저의 작동 방식이다.
outerFunction이 실행을 마치고 반환하는 innerFunction가 호출될 때도, innerFunction은 outerFunction의 값을 기억하고 출력한다.
결론은 클로저는 이러한 방식으로 외부 함수의 변수를 기억하고 사용할 수 있게 해준다.
다시 돌아와서 처음 예제에 대입을 해서 보면
allowToggle는 toggleParagraphHandler 밖에 있는 변수이다. 그리고 toggleParagraphHandler 함수 내부에서는 함수 외부에 있는 allowToggle 변수를 사용한다.
자바스크립트는 이 상수에 클로저를 만들고 함수를 정의(생성)할 때 사용하기 위해 allowToggle상수를 저장한다. 이렇게 되면, 다음에 toggleParagraphHandler가 실행되면 저장된 allowToggle 상수를 그대로 사용하게 된다.
함수 내부 allowToggle의 값은 변수가 저장된 시점의 값을 사용하게 된다.
정리
useCallback에서 클로저 개념을 활용하는 부분은 dependencies 배열이다.
useCallback은 콜백 함수와 dependencies 배열을 기억하고, 콜백 함수 내에서 참조하는 변수들의 이전 값을 유지한다.
따라서 콜백 함수가 클로저로써 이전 환경 정보를 유지합니다.
✅ useCallback은 자바스크립트의 클로저 개념을 활용해서 함수를 메모이제이션을 하고, 필요한 경우에 이전에 생성된 함수를 반환함으로써 성능을 향상시키는 역할을 한다.
'React' 카테고리의 다른 글
useImmer (1) | 2023.08.02 |
---|---|
React에서 map(배열)의 index를 key 값으로 하면 안되는 이유 (4) | 2023.07.20 |
useEffect, useCallback 차이 (0) | 2023.07.14 |
[React] JSX 제한사항 (Fragment) (0) | 2023.05.02 |