useCallback으로 useEffect 심화 활용 해보기
useCallback은 함수를 메모이제이션(memoization) 하기 위해서 사용되는 Hook 들이다. React의 useCallback을 useEffect와 함께 사용하여 여러방면으로 효율적인 코드를 구성할 수 있는 방법이 있다. useCallback은 useEffect와 생긴 것은 똑같지만, 역할은 조금 다르다.
예제로 보는 useEffect 심화 활용
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useCallback을 살펴보자면 첫 번째 인자로 콜백함수를 넣어주고, 두 번째로 인자로 의존성 배열을 넣어준다. a나 b가 바뀌었을 때만 useCallback의 콜백 함수를 새로 생성하고, 그렇지 않을 경우 콜백 함수를 생성하지 않는다.
useCallback을 useEffect와 함께 사용하는 예
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
useEffect(() => {
memoizedCallback();
}, [memoizedCallback]);
useEffect의 의존성 배열에 memoizedCallback이 있고, 콜백함수에서 memoizedCallback을 호출하고 있다.
memoizedCallback는 a, b에 의존적이므로, a와 b가 변경이 생겼을 때만 생성될 것이고, useEffect는 memoizedCallback이 새로 생성되었을 때 memoizedCallback을 호출할 것이다.
useEffect(() => {
doSomething(a, b);
}, [a, b]);
여기서 useCallback은 왜 사용할까?
사실, 위 코드는 앞서본 코드와 같은 형태를 띠게 된다. 음 훨씬 간단해 보인다. 그렇다면 왜 useCallback을 사용할까?
- useEffect에서 하는 행동이 많아질수록 코드가 복잡해진다.
- dependency array가 길어 질 수 있다.
- 추후에 유지보수를 하려하면 헷갈리게 될 수 있다.
useEffect는 우리가 원하는 side effect를 실행만 해주고,useCallback에서 실제 해야 하는 것들을 선언해주면 코드의 분리가 가능하다.- 콜백 함수의 구체적인 역할을 이름을 통해 명시적으로 확인할 수 있다.
- 코드를 정리하고 가독성을 높여서 유지보수를 수월하게 해 줄 수 있다.
state가 바뀔 때마다 데이터를 받아와야 하는 경우
1. useEffect만 사용하는 예
useEffect(() => {
const getDate = async () => {
const response = await fetch('some url');
setData(response.data);
};
getData();
}, [someDeps]);
useEffect의 콜백함수는 Promise를 반환하는 비동기 함수가 될 수 없다. 때문에, getData라는 비동기 함수를 useEffect가 실행될 때마다 생성해주고, 그 안에서 데이터를 가져오고 setData를 해주게 된다. 그리고 만든 getData라는 함수를 실행하게 된다. useEffect가 실행될 때마다 매번 함수가 생성되고 실행되니 매우 비효율적으로 볼 수 있다.
2. useEffect + useCallback 조합한 예
const getData = useCallback(async () => {
const response = await fetch('some url');
setData(response.data);
}, [someDeps]);
useEffect(() => {
getData();
}, [getData]);
결론
useCallback을 활용하면, useCallback안에서 데이터를 가져오는 콜백 함수를 getData에 넣어주고, useEffect안에서는 getData만 호출을 해주면 코드가 훨씬 깔끔해지고, 로직도 분리되며 가독성이 올라가는 효과를 얻을 수 있다.
