useCallback 과 useMemo를 정리한 블로그들을 몇번 보다보면 항상 필수적으로
메모이제이션이라는 개념을 먼저 알려준다
메모이제이션(memoization)이란?
기존에 수행한 연산의 결과값을 어딘가에 저장해두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법
memoization을 적절히 적용하면 중복연산을 피할 수 있기 때문에
메모리를 조금 더 쓰더라도 애플리케이션의 성능을 최적화 할 수 있다.
-React에서 컴포넌트가 렌더링하는 규칙에는 크게 3가지가 있다
1. state나 props가 변경되었을 때
2. forceUpdate() 실행했을때
3. 부모 컴포넌트가 렌더링 되었을 때
애플리케이션의 규모가 커지면서 리렌더가 점점 더 잦아진다면 이는 서비스 사용에 불편을 초래한다.
따라서 리렌더가 일어나지 않도록 최적화 해주는 것이 중요하다
React에서 메모이제이션을 하는 대표적인 방법으로는 useCallback, useMemo, React.memo가 있다
useCallback()
메모이제이션 된 ' 함수 '를 반환한다
사용법
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
-useCallback은 메모이제이션 된 콜백을 반환한다
-컴포넌트 내부에 있는 컴포넌트가 렌더링 될 때 다시 함수를 생성한다.하지만 useCallback으로 감싸주게 되면 첫 렌더링 할 때에만 생성하고 그 이후에는 함수를 기억하고 있어 재생성하지 않는다
-dependency 배열에는 어떠한 값이 변경되었을 때 다시 생성해준다는 뜻으로 새로운 값으로 함수를 실행해야 한다면 반드시 그 값을 해당 의존성 배열에 넣어줘야 한다.
→deps가 변한다면 useCallback 안에 있는 새로운 함수를 반환한다.
예제
import React, {useState, useCallback, useMemo} from "react";
const App = () => {
const [num, setNum] = useState(0);
const [why, setWhy] = useState(0);
//useCallback 이 ()=>{console.log(why)}라는 함수를 반환한다
const useCallbackReturn = useCallback(() => {console.log(why)}, [ex]);
useCallbackReturn();
return(
<>
<button onClick={() => setEx((curr) => (curr + 1))}> X </button>
<button onClick={() => setWhy((curr2) => (curr2 + 1))}> Y </button>
</>
)
}
위의 useCallback은 () => {console.log(why)} 라는 함수를 반환해주고 있다
위 함수는 다음과 같은 순서로 진행된다
1. 처음 컴포넌트가 렌더링 될 때 () => {console.log(0)}
2. ex 가 변할 때까지 함수는 () => {console.log(0)}
3. ex가 변한다면 그제서야 why의 값을 가져와서 () => {console.log(새로운 why의 값)}
Y버튼을 5번 누른다면 useState why의 값은 5가 되지만 useCallback의 함수는 () => {console.log(0)} 상태이다
이 후 X 버튼을 누른다면 useState ex의 값이 변하고 () => {console.log(5)} 를 반환한다
deps에 넣어놓은 값이 변해야 함 컴포넌트와 상태값(why)를 공유하는 것이다
→useCllback은 함수와는 상관 없는 상태값이 변할 때, 함수 컴포넌트에서 불필요하게 함수를 업데이트하는 것을 방지해준다(useEffect와 다른점이 이것이라고 생각함)
-useCallback이 반환한 두 함수는 형태가 같더라도 아예 새로운 함수를 반환한다.
바라보는 값만 같을 뿐, 전혀 다른 메모리를 가진 변수가 된다
useMemo()
메모제이션된 ' 값 '을 반환한다
사용법
const memoizedValue = useMemo(() => callbackFunction(a, b), [a, b]);
-렌더링하는 과정에서 특정 값이 바뀌었을 때만 계산을 실행하고, 원하는 값이 바뀌지 않았다면 이전에 계산한 값을 그대로 사용한다. useCallback과 마찬가지로 dependency 배열에 값을 넘긴다
-useMemo는 deps가 변한다면 내부의 콜백함수를 실행하고, 그 함수의 반환 값을 반환한다.
예제
import React, {useState, useCallback, useMemo} from "react";
const App = () => {
const [num, setNum] = useState(0);
useMemo(() => {console.log(ex)}, [ex]);
return(
<>
<button onClick={() => setEx((curr) => (curr + 1))}> X </button>
<button onClick={() => setWhy((curr2) => (curr2 + 1))}> Y </button>
</>
)
}
useMemo(() => {console.log(ex)}, [ex]) 에서 deps는 ex이다.
즉, ex가 변할 때에만 () => {console.log(ex)}이 실행된다
따라서 X 버튼을 눌르 때에만 콘솔창에 ex값이 출력된다
Y버튼을 누르더라도 APP 이라는 함수 컴포넌트가 전부 재실행(리렌더링) 되지만,
ex 라는 값은 변하지 않았기 때문에 useMemo에는 아무런 변화가 없다
참고
'React' 카테고리의 다른 글
| [React] Context API (0) | 2022.10.23 |
|---|---|
| [React] Immer란? (0) | 2022.10.20 |
| CSR(Client Side Rendering)과 SSR(Server Side Rendering) (0) | 2022.10.20 |
| SPA(Single Page Application) vs MPA(Multi Page Application) (2) | 2022.10.18 |
| [Hook] useState, useEffect 상태값과 생명주기 (0) | 2022.10.13 |
댓글