00:00영상 개요(영상 속 내용과는 무관한 필기)
React의 useMemo hook을 설명하는 영상에 대해 요약 및 번역에 집중한 해설노트입니다.
더욱 자세한 정보는 리액트 공식문서의 useMemo 파트를 참조해보세요!
https://reactjs.org/docs/hooks-reference.html#usememo
00:00*영상과 관련 없는 useMemo에 대한 배경지식들입니다. 만약 useMemo에 대해 익숙하지 않으시다면 해당 노트는 나중에 읽으시거나 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
01:07영상 시작(해당 부분부터 영상을 시청해주세요)
useMemo 설명을 위한 예제코드를 보여줍니다.
number, dark라는 두 개의 state가 존재하는 App 컴포넌트인데요, 우측 화면의 input으로 숫자를 바꾸거나 change theme 버튼으로 색상을 바꾸면 state가 update되면서 App 컴포넌트가 re-rendering 됩니다.
컴포넌트가 rendering 되면 함수들도 전부 재실행되는데요, slowFunction 같은 함수가 존재한다면 컴포넌트가 rendering될 때마다 성능적으로 큰 이슈가 되는 거겠죠.
03:21useMemo가 이 문제를 해결해줍니다.
값을 caching해서 컴포넌트의 매 rendering마다 특정 함수(개발자가 지정하는)의 결과 값을 위해 함수를 다시 실행 할 필요가 없도록 만들어줍니다.
변수 doubleNumber의 경우 slowFunction의 결과입니다. 그리고 slowFunction은 number의 값에 의존해서 결과 값이 결정됩니다. 즉 number가 변하지 않으면 slowFunction의 결과 값도 변하지 않게 되는 것이죠. 하지만 number의 값이 변하지 않아도 dark라는 state가 update될 때마다 slowFunction의 재실행을 유발한다는게 문제죠. 그래서 dark가 update될 때는 slowFunction이 재실행되지 않도록합니다. useMemo를 사용해서 말이죠. useMemo로 slowFunction을 감싸주고 dependancy array에 number를 넣어주면 number가 update 될 때만 slowFunction을 재실행해서 doubleNumber에 새 값을 주게 됩니다.
04:41useMemo가 적용된 후 차이점을 확인
Change Theme 버튼을 누를 때는 이제 delay 없이 즉시 UI에 반영이 됩니다. dark state가 update 돼도 slowFunction가 재실행 되지 않기 때문입니다.
05:28useMemo를 사용하면 항상 좋은 것 아닐까요? 그건 아닙니다.(performance, memory overhead)
useMemo로 인해 컴포넌트가 렌더링 될 때마다 호출해야할 함수가 하나 늘어나는 것이고 이전 렌더링에서의 특정 값을 저장하게 되는 것입니다. 이는 메모리 사용량을 늘리며 필요로 하는 성능을 높이는 일입니다.
그렇기 때문에 useMemo는 성능적인 이점이 있을 때만 사용하는 것이 바람직합니다.(매우 느린 함수를 실행해야할 때)
06:32useMemo를 사용하는 두 번째 상황: referential equality
javascript에서는 값을 비교하는 기준으로 value와 reference가 있다고합니다. object, array의 경우 value(내용)가 같아도 참조하는 reference가 다르면 다르다고 취급이 되는데요(영상 속 themeStyles, themeStyles2가 다른 이유), useMemo로 themeStyles를 memoization한다면 직전 렌더링에 사용된 themeStyles와 referential equality 하게 되고 useEffect는 호출되지 않게 됩니다.(themeStyles가 변하지 않았으므로)
useMemo를 사용하지 않는다면 매 렌더링마다 useEffect내의 console.log가 수행될 것입니다. 왜냐하면 매 렌더링마다 새롭게 만들어지는 객체(themeStyles)는 값(내용)이 같아도 다르게 취급되고 이는 useEffect가 매번 실행되게 만들기 때문입니다. 하지만 useMemo가 감싸면 매번 새롭게 만드는게 아니고 이전 렌더링의 themeStyles를 사용하는 것이기 때문에 useEffect가 호출되지 않겠죠?(useMemo의 depenancy array에 들어있는 dark가 바뀌지 않는 이상)
*여기서는 useEffect의 dependancy array를 예시로 들었지만 컴포넌트의 prop에 대해서도 referential equality를 따지므로 useMemo는 prop과 관련해서도 쓰일 수 있습니다.
09:44영상 요약(useMemo는 언제 쓰이나)
1. 대부분의 경우, 실행에 매우 많은 시간이 소요되는 함수를 useMemo로 감싸서 사용한다. 이렇게 되면 매번 재실행할 필요가 없어진다.(함수에 들어가는 param이 변할 때만 재실행되어야함)
2. referential equality가 보장되어야할 때 (example: useEffect의 dependancy array, 컴포넌트의 prop)
해당 학습노트에서는 react router 버전6에서 redirect를 어떻게 구현하는지 소개합니다.
공식 문서: https://reactrouter.com/
00:50
react router 버전5에서 redirect를 구현하는 방법입니다.
*예상 시나리오: pathname이 '/redirect'인 page 접근 시 pathname '/about'인 page로 전환됨
*특정 pathname에 redirect 로직을 등록하는 이유는 가지각색이겠지만 그 중 대표적인 용도는 로그인 여부 검사입니다. 서비스를 이용하는 유저가 로그인을 했을 경우 특정 pathname에 접근하지 못하도록 사용하는 것이죠.