useMemo
useMemo 란 값을 캐싱(메모이제이션)하는 리액트의 훅입니다.
useCallback 과 다른점은 useCallback 은 함수를 캐싱하고 useMemo 는 값 자체를 캐싱합니다.
첫번째 인자로 함수를 받고 두번째 인자로 의존성 배열을 받습니다.
useMemo 사용 예시
import React from 'react';
import { useState } from 'react';
export default function App() {
const [count1, setCount1] = useState(0);
const [count2, setCount2] = useState(0);
const countValue = count1*count1
return (
<div>
<button onClick={() => setCount((prev) => prev + 1)}>count1</button>
<button onClick={() => setCount2((prev) => prev + 1)}>conunt2</button>
<div>Value 1 : {count1}</div>
<div>Value 1 : {count2}</div>
<div>Value 1 * Value 1: {countValue}</div>
</div>
);
}
위 코드는 count1,count2 라는 두개의 상태가 있고 count1 두개를 곱하는 값이 있습니다.
countValue 는 count2 와 전혀 상관없는 상태이지만 count2 를 증가시키게되면 countValue 도 다시계산을하게됩니다. 상태가 변화했기 때문에 컴포넌트 전체가 리렌더링 되기 때문이죠.
위의 예시는 단순 계산이라 성능에 큰 영향은 미치지 않겠지만 만약 복잡하고 오래걸리는 계산이라면 당연히 성능이 나빠질것입니다.
이럴때 사용하는것이 값을 캐싱(메모이제이션) 해주는 useMemo 를 사용하면 됩니다.
const countValue = useMemo(() => {
console.log(count1 * count1);
return count1 * count1;
}, [count1]);
countValue 는 count1 에 영향을 받는 값이니 의존성배열에 count1 상태가 변화할때 실행하도록 해주시면 됩니다.
useCallback
useCallback 이란 값이 아닌 "함수"를 캐싱 할 때 사용하는 훅입니다.
useCallback 왜 사용할까?
React 함수 컴포넌트 안에 어떤 함수가 선언이 되어 있다면 이 함수는 해당 컴포넌트가 랜더링될 때 마다 새로운 함수가 됩니다.
함수의 내용이 바뀌지 않았음에도 불구하고 계속 새로운 함수로 참조값이 바뀌게 되는 것 입니다.
하지만 useCallback를 사용하면 해당 컴포넌트가 랜더링 되더라도 그 함수가 의존하는 값들이 바뀌지 않는이상 기존 함수를 계속하여 반환합니다.
const add = useCallback(()=>x+y,[x,y])
하지만 컴포넌트가 랜더링 될때마다 새로운 함수를 선언하는것은 성능에 큰 영향을 미치지 않을수 있습니다.
그럼 어떤 상활일때 성능 향상을 기대할 수 있을까요?
import React, { useState, useEffect } from "react";
function Profile({ userId }) {
const [user, setUser] = useState(null);
const fetchUser = () =>
fetch(`https://your-api.com/users/${userId}`)
.then((response) => response.json())
.then(({ user }) => user);
useEffect(() => {
fetchUser().then((user) => setUser(user));
}, [fetchUser]);
// ...
}
위 코드를 예시로 설명해보겠습니다.
fetchUser 는 함수로 정의 되어있으며 useEffect의 의존성배열에 주입되어있습니다. useEffect 안에서 user의 상태를 변화 시켯기때문에 Profile 컴포넌트는 리렌더링을 시작합니다. 이때 fetchUser의 참조값이 바뀌므로 useEffect가 다시 실행되어 또 다시 호출을하게되며 계속 API 호출을 하는 무한루프에 빠지게 됩니다.
import React, { useState, useEffect } from "react";
function Profile({ userId }) {
const [user, setUser] = useState(null);
const fetchUser = useCallback(
() =>
fetch(`https://your-api.com/users/${userId}`)
.then((response) => response.json())
.then(({ user }) => user),
[userId]
);
useEffect(() => {
fetchUser().then((user) => setUser(user));
}, [fetchUser]);
// ...
}
앞선 무한루프 예시에 상황일때 useCallback 을 사용합니다.
Profile 컴포넌트가 렌더링될때 fetchUser 함수가 useEffect 안에서 실행되어 user의 상태를 바꾸고 리렌더링이 됩니다.
여기서 위와 다르게 userId를 useCallback의 의존성배열로 주입해주었기때문에 userId 가 바뀌지 않는한 재호출되지 않을것입니다.
useMemo와 useCallback 를 다시한번 정리해보았습니다 둘의 생김새가 비슷하여 헷갈린적이 많았는데 이번기회에 확실히 알게되었습니다.
useMemo = 값을 캐싱 !
useCallback = 함수를 캐싱 !
'React' 카테고리의 다른 글
React-Query - onClick 이벤트로 useQuery data fetching (0) | 2023.10.09 |
---|---|
React- 재사용성과 확장성을 높이는 리액트 컴포넌트 설계 하기 (1) | 2023.09.25 |
React - 리액트 해시태그 구현 (0) | 2023.09.23 |
리액트 라이브러리없이 달력(Calender) 구현 with "date-fns" (0) | 2023.09.12 |
React - React-hook-form 회원가입시 닉네임 중복검사 하는법 (0) | 2023.06.05 |