지금까지 만든 것을 살펴보면 잘 동작하는 것처럼 보이지만
한가지 문제점이 있다.
콘솔창을 확인해보면
useEffect Hook에서 handleLoad라는 디펜던시가 빠져있다고 한다.
이 메세지는 개발모드에서 코드를 검사해서 알려주는 것
react-hooks/exhaustive-deps라는 규칙을 어겼다는 의미이다.
필요한 daps를 빠짐없이 넣어주야한다는 규칙
버그가 생기는 것을 막을 수 있기때문에 되도록이면 지켜주는 것이 좋다.
일단 handleLoad를 디펜던시에 추가해준다.
저장하고 확인해보면 무한루프가 발생하고 있다.
사실 함수를 그냥 디펜던시 리스트에 추가하면 무한루프가 발생한다.
새로운 콘솔 경고창이 생기는 데
handleLoad함수가 디펜던시로 추가되었는데 렌더링할 때마다 매번 바뀌니까
useCallback Hook을 사용하라고 알려주고 있다.
handleLoad함수를 살펴보면 렌더링할 때마다 매번 새로 만든다.
그래서 이 값을 디펜던시로 추가하면 문제가 되는 것이다.
처음 렌더링하고 나서 useEffect 콜백을 실행하면
State 값이 바뀌어서 다시 렌더링하게 되는데 이때 handleLoad함수를
새로 만들기 때문에
디펜던시 리스트의 값이 달라지게 된다.
그래서 useEffect의 콜백이 다시 실행되고 이때 State가 변경되면서 다시 렌더링되고
handleLoad함수가 새로 만들어지면서 또다시 useEffect 콜백이 실행되는
무한 루프가 발생하게 되는 것이다.
이럴 때 사용하는 Hook이 useCallback이다.
useCallback을 사용하면 함수를 기억해두었다가 함수를 재사용할 수 있다.
useCallback이라는 함수는 첫번째 아규먼트로는 고정시킬 함수를,
두번째 아규먼트로는 디펜던시 리스트를 넘겨주면 된다.
그럼 return값으로 함수를 return해준다.
이때 디펜던시 리스트는 useCallback에 전달할 함수를 언제 새로 생성할 것인지를
판단하는 기준이된다.
이렇게 useCallback으로 지정한 함수는 리액트에서 기억해두기때문에
디펜던시 리스트의 값이 그대로라면 함수를 새로 만드는 것이 아니라
재사용하게 된다.
저장하고 확인해보면 무한루프가 발생하지 않는다.
그러나 콘솔창에 또 다른 경고창이 뜨는데
useCallback에 디펜던시로 getReviewsAsync함수가 빠져있다고 한다.
이중에서 리액트에서 제공하는 setter함수인 setItems, setOffset, setHasNext는
따로 디펜던시 리스트에 추가해줄 필요가 없다.
그래서 getReviewsAsync 함수만 디펜던시 리스트에 추가해야한다고 알려준 것이다.
getReviewsAsync를 디펜던시 리스트에 추가해주고
혹시 getReviewsAsync 함수도 매번 새로 만드는 것은 아닌지 확인해야한다.
그래서 getReviewAsync 선언된 코드를 살펴보면
useAsync 함수를 사용하고 있고
useAsync함수에 들어가서 코드를 살펴보면 wrappedFunction에 해당하는 함수인데
이 함수도 매번 새로 만들고 있다
그래서 이것도 useCallback으로 감싸준다.
그럼 wrappedFunction에서 바깥으로 참조하는 값은
asyncFunction함수를 참조하고 있다.
asyncFunction이 바뀌면 wrappedFunction도 새로 만들어야 하니까
디펜던시 리스트에 넣어준다.
다시 App.js파일로 가보면
useAsync를 사용할 떄 getReviews라는 함수를 아규먼트로 넘겨주고 있는데
이 함수는 한번 선언되고 나면 변하지 않는 값이기 때문에
이 경우에는 디펜던시 리스트에 값도 변하지 않고 그래서 useCallback으로 만들어진
wrappedFunction의 함수도 변하지 않는 값이 된다.
즉, getReviewsAsync의 값은 항상 같은 값이다.
마찬가지로 handleLoad함수도 디펜던시 리스트에 있는 getReviewsAsync값이
변하지 않기때문에 항상 같은 값이 된다.
그래서 useEffect에 handleLoad함수를 디펜던시에 추가하더라도
handleLoad값이 바뀌어서 useEffect의 콜백이 실행되지 않는다.
이때 매번 생성하는 함수는 디펜던시 리스트로 쓸 수 없기 때문에
useCallback이라는 Hook으로 함수를 고정시킬 수 있었다.
이렇게 useCallback은 함수를 매번 새로 만들지 않고
재사용하게 해주는 Hook이다.