00:00영상 개요(영상 속 내용과는 무관한 필기)
React의 useCallback hook을 설명하는 영상에 대해 요약 및 번역에 집중한 해설노트입니다.
더욱 자세한 정보는 리액트 공식문서의 useCallback 파트를 참조해보세요!
https://reactjs.org/docs/hooks-reference.html#usecallback
00:00*영상과 관련 없는 useCallback에 대한 배경지식들입니다. 만약 useCallback에 대해 익숙하지 않으시다면 해당 노트는 나중에 읽으시거나 skip해주세요.
배경지식:
얕은 비교(shallow comparison)란 간단히 말하자면 객체, 배열, 함수와 같은 참조 타입들을 실제 내부 값까지 비교하지 않고 동일 참조인지(동일한 메모리 값을 사용하는지)를 비교하는 것을 뜻한다. 객체(object), 배열(array), 함수(function)와 같은 객체들은 같은 참조 값이 아니라면 새로운 값으로 판단하는 것이다.
배경지식 2:
리액트 개발을 하실 때, `useCallback`, `useMemo`, `React.memo` 는 컴포넌트의 성능을 실제로 개선할수있는 상황에서만 하세요.
예를 들어서, User 컴포넌트에 `b` 와 `button` 에 `onClick` 으로 설정해준 함수들은, 해당 함수들을 `useCallback` 으로 재사용한다고 해서 리렌더링을 막을 수 있는것은 아니므로, 굳이 그렇게 할 필요 없습니다.
출처: https://react.vlpt.us/basic/19-React.memo.html
00:38영상 시작
예제 App 컴포넌트 소개
*해당 강의는 React 코드를 토대로 진행됩니다.
02:36input tag에 숫자를 입력/변경 시에 console 창에 'Updating Items'가 출력되는 것을 확인할 수 있습니다.
02:42뿐만 아니라 Toggle theme 버튼을 눌러도 console 창에 'Updating Items'가 출력됩니다.
02:48유튜버는 Toggle theme 버튼을 누를 때도 console 창에 'Updating Items'가 출력되는 것이 문제라고 말하며 useCallback hook으로 개선 가능하다고 합니다.
*02:54부터는 본인의 useMemo 관련 영상을 먼저 보라는 안내가 이어집니다. 해당 영상과는 별개의 내용이므로 03:04 해설노트로 바로 jump할까요?
03:04console 창에 'Update Items'가 출력되는 이유는 App 컴포넌트가 re-rendering 되면서 getItems 함수가 매번 재생성돼서 그렇다고 말합니다.
03:23그리고 App 컴포넌트의 re-rendering으로 인해 매번 새롭게 생성되는 getItems 함수가 List 컴포넌트의 prop으로 전달되면서 List 컴포넌트의 useEffect가 List 컴포넌트가 호출될 때마다 재실행 되는 것이라고 말합니다.
*여기까지의 코드에서는 getItems 함수를 실행했을 때 같은 결과를 낸다하더라도 다르게 취급해서 useEffect는 계속 실행됩니다.(referential equality)
*함수 내용이 같다고 해서 두 함수는 같은 것이 아닙니다. JS에서는 primitive한 value(number, bool, string)가 아닐 경우(object, function) 같은 내용이라도 다른 값으로 취급됩니다.
03:46App 컴포넌트에서 생성되는 getItems 함수가 List 컴포넌트의 useEffect의 dependancy array에 속해있는만큼, getItems 함수의 내용이 변하지 않을 때는 getItems 함수를 재생성하지 않도록 App 컴포넌트에서 조치해야합니다.
그렇다면 우선 getItems 함수가 재생성되는 시점을 판단해볼까요? 그것은 바로 App 컴포넌트의 re-rendering입니다. 그리고 re-rendering을 유발하는 것은 setNumber, setDark입니다. 그런데 getItems 함수가 재생성 되어야하는 것은 number가 바뀔 때 뿐이어야하죠?(number가 getItems 함수 내용과 연관이 있으므로) 그렇기 때문에 setDark로 인해 dark가 변경되면서 App 컴포넌트가 re-rendering 될 때는 getItems 함수의 재생성을 방지해야합니다.
03:56useCallback hook을 기존 코드에 적용하는 방법
영상에서는 useCallback으로 getItems 함수를 감싸주었고 dependancy array에 number를 입력했습니다. 이는 App 컴포넌트가 re-rendering되며 함수를 재생성하려 할 때와 관련 있으며! number가 바뀔 때만 getItems 함수를 재생성되게 만듭니다.
04:17useCallback 함수를 적용한 뒤의 변경점
*Toggle theme 버튼을 눌러도 console이 출력되지 않는 이유: Toggle theme 버튼을 누르면 App 컴포넌트는 re-rendering 되지만 getItems 함수는 재생성되지 않습니다.(number가 그대로이므로) 그래서 List 컴포넌트에 넘어가는 getItems도 유지될 것이고 List 컴포넌트의 useEffect가 실행되지 않으면서 console 창에 'Updating Items'가 출력되지 않는 것이죠.
04:49useMemo와의 차이점
useMemo는 인자로 받는 함수의 결과를 반환하며 useCallback은 인자로 받는 함수 자체를 반환합니다.
함수가 인자를 입력 받아야 될 경우, 그리고 이 인자를 하위 컴포넌트에서 입력해줘야하는 경우엔 useCallback이 더 유용합니다.
함수 실행이 오래 걸린다면 useMemo가 더욱 유용할 것입니다.
06:26useCallback을 사용하는 순간은 referential equality를 고려해야할 때, 함수 생성에 오랜 시간이 걸릴 때라고 합니다.
그렇지만 함수 생성에 시간이 오래 걸릴 일은 잘 없을 것이고 주로 referential equality를 고려해야할 때 사용하게 될 것이라고 하네요!
*App 컴포넌트가 re-rendering 될 때 getItems 함수가 재생성되면서 직전 렌더링에 의해 생성된 getItems와 내용이 같아도 다른 함수 취급받게 됩니다. 그래서 List 컴포넌트에 getItems 함수를 prop으로 전달할 때도 useEffect 내의 effect 함수가 실행되는 것이죠(getItems가 dependancy array에 있으므로) useCallback으로 함수를 반환받으면 referential equality를 보장받게 되고 변하지 않은 getItems에 대해 useEffect를 호출하지 않게 됩니다(useCallback의 dependancy array 속 데이터가 변하지 않았다는 가정하에)
해당 학습노트에서는 react router 버전6에서 redirect를 어떻게 구현하는지 소개합니다.
공식 문서: https://reactrouter.com/
00:50
react router 버전5에서 redirect를 구현하는 방법입니다.
*예상 시나리오: pathname이 '/redirect'인 page 접근 시 pathname '/about'인 page로 전환됨
*특정 pathname에 redirect 로직을 등록하는 이유는 가지각색이겠지만 그 중 대표적인 용도는 로그인 여부 검사입니다. 서비스를 이용하는 유저가 로그인을 했을 경우 특정 pathname에 접근하지 못하도록 사용하는 것이죠.