일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 자바스크립트
- CSS
- JS
- til
- 프로그래머스
- Baekjoon
- 프론트엔드
- 자바스크립트 알고리즘 문제
- 알고리즘문제풀이
- 자바스크립트 알고리즘
- lodash
- Next
- 타입스크립트
- react
- 제로베이스
- 자바스크립트 문제 풀이
- 자바스크립트 문제
- HTML
- leetcode문제풀이
- stack문제
- 자바스크립트코딩테스트
- 자바스크립트 문제풀이
- leetcode
- 자바스크립트 연결리스트
- NPM
- 리액트쿼리
- next13
- Next.js13
- JavaScript
- 리액트
- Today
- Total
코드노트
REACT Hooks 노트 React.memo (feat.useMemo, useCallback) 본문
useMemo가 아니라 React.memo? memo는 useMemo만 있는게 아니였나.. 했지만
React.memo도 있었다..
쉽게말하면 불필요한 컴포넌트 렌더링을 방지하는 훅! 그럼 useMemo와는 어떻게 다를까?
React.memo와 useMemo, useCallback을 모두 정리해보려고 한다.
useMemo
const value = useMemo(() => {
return 함수()
}, [item])
------------------------
const value = useMemo(() => {
return 함수()
}, [])
- 첫 번째 인자는 콜백함수를 받는다. 두번 째 인자는 의존성 배열(Dependency)을 받으며,
두번째 인자인 배열의 요소의 값이 업데이트 될 때만 콜백 함수를 다시 호출한다.
* useMemo는 1ms이상 걸리는 경우 사용하자.
- 여기서 두번째 인자에 빈 배열을 넘겨주게 되면 처음 컴포넌트가 마운트 되었을때만 값을 계산하고 이후에는 항상 memoization값을 꺼내 와서 사용하게 된다.
useMemo 사용 예제
- 객체 useMemo
country: isNationality ? "한국" : "외국"
- 객체타입의 값이 변경될때에는 메모리상의 변경이 발생한다. ( 같은 값이라도 메모리상의 공간은 다르기 때문 )
그렇기 때문에 컴포넌트가 객체값이 할당될때에는 메모리상의 변화를 감지하게되고,
useEffect가 의존하고 있는 location은 변화한걸로 간주하여 useEffect내부 로직이 실행된다.
- 즉 number값이 변할때마다 리렌더링이 되면서 location의 값도 변경되고 useEffect가 실행되는 것이다.
- 이럴때 사용할 수 있는게 useMemo이다.
useMemo를 사용하게 되면 useMemo가 의존하고있는 isNationality가 변경될때마다 리렌더링이 되고 그 외에는 값이 변하지 않는다.
- 만약 컴포넌트내부에서 서로 연결되어있지 않고 각각의 상태를 사용하고 있다면 useMemo를 통해서 리렌더링이되는걸 막을 수 있다.
useCallback
- useMemo와 똑같이 내부에 useCallback으로 전달한 콜백함수를 memoization하여 사용해야할때 함수를 사용할 수 있다.
* 가급적 child에게 내려주는 prop의 경우에 사용하자!
리액트 함수형 컴포넌트는 함수이다.
함수형 컴포넌트가 렌더링이 된다는것은? -> 컴포넌트 함수가 호출되는 것! -> 그럼 모든 내부 변수가 초기화된다.
그렇다면 컴포넌트 내부에서 사용하는 함수를 useCallback을 사용해준다면,
컴포넌트가 호출될때마다 함수를 다시호출하지않고 첫 마운트되었을때 사용한 함수를 그대로사용한다.
useCallback(() => {
return value
}, [item])
- 2개의 인자를 받으며, memoization할 함수와 의존성 배열(Dependency)을 사용한다.
- 의존성 배열값이 변경될때마다 함수를 재실행한다.
useCallback 사용 예제
- 현재 예제에서는 input값을 올리게되면 someFunc는 실행되지 않는다.
true,false버튼을 누르게 되면 number의 값이 반영되고 CallsomeFunc버튼을 눌렀을때 console에 변경된 값이 얼마인지 알 수 있다.
- useCallback을 사용하지 않았다면 어떻게 될까?
- input에서 number값을 올리고 내리거나, true, false버튼을 누를때도 someFunc는 실행되기 때문에 불필요한 렌더링이 계속 반복되게 된다.
- 이와같이 함수를 할당하는것도 상태가 변화되는것이기 때문에 같은 함수라도 리렌더링이 될때마다 계속 변화를 감지하고 호출하게 되는것이다.
- 이를 useCallback을 통해서 불필요하게 변하지않은 함수의 리렌더링을 막을 수 있다.
- 이 예제에서는 isDark상태가 바뀔때마다 리렌더링이 되기 때문에 useCallback을 사용하지 않는다면
createBoxStyle 함수가 계속 실행되게 된다.
- Box크기를 조절하는것과는 필요가 없는 함수이지만 마운트될때마다 컴포넌트들이 리렌더링되면서
isDark의 state가 변경되면서 다시 리렌더링이 진행되고 createBoxStyle함수도 재할당되며 변화가 된것처럼 실행된다.
- useCallback을 통해서 size의 상태를 의존성 배열(Dependency) 에 넣어주면 해결!
React.memo
고차컴포넌트 HOC(HigherOrderComponent)
일반 컴포넌트를 React.memo를 통하게 되면 Prop Check를 통하여 자신이 받는 props의 변화가 있는지를 확인한다.
- 렌더링이 될때마다 Prop Check를 통해서 props가 변화가 있는지 없는지를 확인 후 변화가 있다면 리렌더링이 된다.
- memoization된 값을 반환하는 훅
- prop Check를 통해서 변화가 없는 값이면 리렌더링이 되는게 아닌 값을 재사용한다.
- 불필요한 렌더링을 막을 수 있는 훅!
state가 업데이트가 되면 Atomic과 같은 디자인 패턴을 적용한 경우라면?
여러 컴포넌트로 구성되어 있는 페이지는 하나의 state가 업데이트되지만
다른 컴포넌트들도 리렌더링이 될 것이다.
어 그럼 모든 props를 React.memo를 통해 Prop Check해주면 좋지 않을까?라고 생각할 수 있다.
React.memo는 변화된값과 비교해야하기때문에 값을 저장해두게 된다.
무분별하게 사용하게 되면 메모리를 추가적으로 소비하게 된다!
꼭 필요할때만 사용하자!
그럼 어쩔때 사용해야할까?
- 컴포넌트가 같은 props로 자주 렌더링이 될때
- 컴포넌트가 렌더링이 될때마다 복잡한 로직을 처리해야할 때
React.memo는 Props변화에만 의존하는 최적화 방법
useState, useReducer, useContext와 같은 상태관리 훅을 사용한다면
props의 변화가 없다라도 다시 렌더링이 된다. 기억하자!
React.memo 예제
- Child컴포넌트는 childAge State를 props로 받고있다.
parent age를 증가시키는 버튼을 누르게 되면 Child컴포넌트도 리렌더링이 될것이다.
- react.memo는 컴포넌트의 props가 변하지 않는다면 리렌더링을 막아준다. Child컴포넌트를 memo(Child)로 사용하게되면
parent age를 증가시키는 버튼을 누르더라도 Child에게 전해지는 childAge props는 변화가 없기 때문에 리렌더링을 막을 수 있다.
- console을 확인해보면 Child컴포넌트에서 나오는 console은 child age 버튼을 누를때만 실행되는걸 볼 수 있다.
그럼 useCallback, useMemo를 조합하여 최적화를 시켜보자!
- 위 예제에서 객체를 추가하고 함수도 새로 추가하였다.
- React.memo를 통해 Child컴포넌트를 최적화시켰지만 memo는 컴포넌트의 props의 변화만 감지하여
prop check를 진행한다.
* 여기서 꼭 알아야할 것은 객체는 항상 렌더링이 되면서 할당을 할때 메모리값이 변경된다.
* 함수 또한 같은값을 반환하는 순수함수라도 함수또한 객체이기때문에 메모리값이 변경된다.
- 그럼 name은 객체, tellme는 함수이기 때문에 props로 전달하는 값은 변경이 된것처럼 감지된다.
- 그렇기 때문에 name객체는 useMemo를 사용하여 변하지 않는 값을 memoization을 시켜주고,
tellme함수또한 useCallback으로 memozaition을 시켜주면 불필요한 렌더링을 줄일 수 있었다.
useMemo, useCallback 그리고 React.memo는 꼭 필요할때만 사용해야하고
사용하기전에 꼭 필요할까?라는 생각을 다시한번 해보자..!
불필요한 렌더링을 막을 수는 있지만 객체, 함수, 컴포넌트를 따로 저장하면서 메모리를 사용하기때문에
그또한 불필요한 memoization이 될 수 있다는걸 명심하자.!!!
'Code note > 리액트' 카테고리의 다른 글
Redux의 구조 정리, feat. Flux 패턴 (0) | 2023.07.24 |
---|---|
리액트(컴포넌트) 에러처리 ErrorBoundary ... class... (1) | 2023.04.12 |
REACT Hooks 노트 useReducer 정리 (0) | 2023.03.16 |
REACT Hooks 노트 custom hook (form control) (0) | 2023.03.13 |
REACT Hooks 노트 useContext + Context API 정리 (1) | 2023.03.11 |