일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 코테
- 코딩테스트
- await
- 완전탐색
- webpack
- pjax
- react internals
- web
- React.memo
- python
- useEffect
- useState
- eslint
- useMemo
- VanillaJS
- Permutations
- 비동기
- react
- BFS
- 프로그래머스
- venv
- VanillJS
- prettier
- 그리디
- canvas
- seo
- useCallback
- Hook
- 환경설정
- Custom Hook
- Today
- Total
Amada Coding Club
[React Hook] 리액트 Hook 총정리(5) - useMemo useCallback (React.memo) 본문
[React Hook] 리액트 Hook 총정리(5) - useMemo useCallback (React.memo)
아마다회장 2023. 1. 28. 18:502023.01.28 - [Front-End/React] - [React Hook] 리액트 Hook 총정리(4) - Hook 사용 규칙, Hook 제작방법
지난 글에 이어서..
제일 내 머릿속을 뒤흔드는 useMemo와 useCallback에 대해 알아보자
우선 요약하자면
useMemo는 메모이제이션된 값을 반환하고
useCallback은 메모이제이션된 함수를 반환한다.
그리고 useMemo(() => function, dependencies) 와 useCallback(function, dependencies)는 같다.
들어가기 전에 우선 앞에서 언급된 메모이제이션에 대해 알아보자
메모이제이션
메모이제이션(memoization)은 기존에 수행한 연산값을 저장하고 동일한 입력이 들어왔을 때 저장된 연산값을 재사용하는 프로그래밍 기법이다. 잘 사용하기만 한다면 중복 연산을 막아줘 프로그램의 성능 향상을 도울 수 있다.
useMemo
위에서 봤다시피 useMemo는 메모이제이션된 값을 반환하는 Hook이다. 이때 메모이제이션은 즉, useMemo는 기존에 수행된 값을 반환하면서 연산이 중복 실행되는 것을 막아준다. 형태는 다음과 같다
useMemo(()=>func, [deps])
deps는 dependecies로 의존성을 가지는 값(함수도 포함)이다. 다시 말해 useMemo는 deps값에 의존해서 작동하며 deps값이 변할 때 ()=> func가 실행되어 func가 반환된다. deps가 변하지 않았을 경우에는 기존에 메모제이션된 값이 반환되며(실행되지 않는다는 말이 아니다!!) 값을 사용할 수 있다 예시를 보자
function App(){
const [countx, setCountx] = useState(0);
const [county, setCounty] = useState(0);
useMemo(() => {console.log(`x: ${countx}`)}, [countx])
useMemo(() => {console.log(`y: ${county}`)}, [county])
return(
<>
<button onClick={() => setCountx(prev => prev+1)}>X</button>
<button onClick={() => setCounty(prev => prev+1)}>Y</button>
</>
)
}
사진과 같이 X를 클릭할 경우에는
x의 값만 출력되는 것을 알 수 있다.
x를 클릭하면 deps의 변화를 감지해 () => {console.log(`x: ${countx}`)}를 실행하고
y관련 useMemo는 실행하지 않고 기존의 값을 사용하기 때문에 콘솔창에 뜨지 않게 된다.
useCallback
useMemo는 값을 반환한 것(함수를 실행함)과 달리 useCallback은 함수(콜백)를 실행하지 않고 반환한다.
형태는 useMemo와 유사하다.
useCallback(func, [deps])
useCallback또한 deps가 변경될 때 새로운 func을 반환한다.
바로 예시를 보자
function App(){
const [countx, setCountx] = useState(0);
const [county, setCounty] = useState(0);
const f = useCallback(() => {console.log(`y: ${county}`)}, [countx])
f();
return(
<>
<button onClick={() => setCountx(prev => prev+1)}>X</button>
<button onClick={() => setCounty(prev => prev+1)}>Y</button>
</>
)
}
약산 다르게 해봤다. countx가 변하면 새로운y값이 담긴 callback을 반환한다. 즉, x를 클릭하지 않으면 기존의 함수를 계속 사용하기 때문에 y값인 0을 콘솔창에 출력한다는 말이다!
처음 실행할 때 useCallback은 console.log(0)을 가지고 있기 때문에 계속 0이 출력되고 x를 눌렀을 때 현재 y의 값을 가진 console.log를 반환하기 때문에 값이 업데이트되는 것이다.
왜 필요할까?
컴포넌트는 부모 컴포넌트에서 기존과 다른 값을 보내거나 안에 state가 업데이트될 때마다 안에 있는 함수들을 렌더링(재실행)을 한다. 가벼운 프로그램에서는 상관없지만 복잡한 함수들이 많은 경우에는 불필요한 렌더링은 성능저하를 일으킨다. 그 불필요한 렌더링을 막고 해당 함수에서 사용하는 값이 변경될 경우에만 함수를 렌더링해 성능을 높이기 위해 사용한다.
React.memo - props가 변할 때만 렌더링
추가적으로 컴포넌트 자체의 불필요한 렌더링을 막아주는 React.memo에 대해 알아보자
리액트는 컴포넌트에서 또다른 컴포넌트를 반환하는 고차 컴포넌트(HOC: Higher Order Component)를 지원한다
function F(){
return(
<Component props />
)
}
이런 느낌으로.. 이때 상위 컴포넌트가 렌더링되면 하위 컴포넌트도 자동으로 리렌더링이 된다. 만약에 상위에서만 렌더링이 필요하고 하위에는 동일한 props값을 전달할 경우에는 불필요한 렌더링이 발생할 수 있다. 이를 막아주고 props값이 바꼈을 때만 하위 컴포넌트의 렌더링을 해주는 함수(?) 기능(?)을 React.memo라 한다.
사용하는 방법은 간단하다 하위 컴포넌트를 export할 때 React.memo를 감싸주면 된다.
export default React.memo(Component)
이렇게 사용하면 해당 컴포넌트의 props값이 변할 때 컴포넌트의 렌더링을 발생시킨다.
그러나 props값을 비교할 때, shallow compare를 한다 일반 정수, 문자열과 같은 props은 문제가 되지 않지만, 객체나 함수의 경우 안에 내용이 아닌 주소값을 비교하기 때문에 props값이 전해질 때마다 다른 값으로 인식될 수 있다. (예를 들어 useCallback에서 함수가 반환될 때 이는 각각 주소가 다르기 때문에 다른 함수로 인식한다. 이를 하위 컴포넌트로 보낸다면 불필요한 리렌더링을 일으킬 수 있다.) 그래서 React.memo의 두 번째 인자로 비교하는 방법을 설정할 수 있다.
export default React.memo(Component, compare(prev, next)) //compare함수는 별도로 구현
그러면 뒤에 값이 false일 때만 리렌더링을 일으키게 된다.
이 React.memo는 언제 사용하면 좋을까?
상위 컴포넌트가 렌더링이 일어나도 하위 컴포넌트의 props값은 잘 변하지 않을 때 사용하면 성능 향상을 얻을 수 있다.
언제 사용하면 안될까?
props가 자주 변하는 환경에서 사용하면 오히려 성능 저하를 일으킬 수 있다.
이렇게 간단하게 세 가지에 대해 알아봤다. useCallback이나 useMemo나 memo나 무조건적인 성능 향상을 얻는 것은 아니라는 사실을 명심하고 조심히 써야겠다.
다음은 useRef, useContext에 대해 알아보자
참조
https://ideveloper2.tistory.com/159
https://ko.wikipedia.org/wiki/%EB%A9%94%EB%AA%A8%EC%9D%B4%EC%A0%9C%EC%9D%B4%EC%85%98
https://cocoon1787.tistory.com/799
https://react.vlpt.us/basic/19-React.memo.html
https://ui.toast.com/weekly-pick/ko_20190731
https://whales.tistory.com/117
https://leehwarang.github.io/2020/05/02/useMemo&useCallback.html
https://yceffort.kr/2022/04/best-practice-useCallback-useMemo
'Front-End > React' 카테고리의 다른 글
[React Hook Context API] 리액트 Hook 총정리(6) - useContext (Context API) (0) | 2023.02.02 |
---|---|
[create react app / heroku 배포 오류] heroku22 배포 오류 (0) | 2023.01.31 |
[React Hook] 리액트 Hook 총정리(4) - Hook 사용 규칙, Hook 제작방법 (0) | 2023.01.28 |
[React Hook] 리액트 Hook 총정리(3) - useEffect (0) | 2023.01.20 |
[React Hook] 리액트 Hook 총정리(2) - useState (0) | 2023.01.20 |