본문 바로가기

React/이론공부

[React Hooks] useMemo

useMemo 란

컴포넌트의 성능을 최적화시킬 수 있는 대표적인 react hooks 중 하나

useMemo 의 Memo 는 Memoization 을 뜻함

memoization이란
- 기존에 수행한 연산의 결괏값을 어딘가에 저장해 두고 동일한 입력이 들어오면 재활용하는 프로그래밍 기법
- 자주 사용되는 값을 캐싱해두어서, 필요할 때마다 다시 계산하는게 아니라, 재사용하는 것

 

함수형 컴포넌트에 대해

- 함수형 컴포넌트는
렌더링 -> component 함수 호출 -> 모든 내부 변수 초기화 과정을 거친다.

 

UseMemo 를 사용했을 때 함수형 컴포넌트 모습

const calculate = () => {
  return 10
}

function App() {
  const value = useMemo(() => {
    calculate()
  }, [])

  return (
    <div>
      { value }
    </div>
  );
}

1. 렌더링

2. component 함수 호출 (Memoization)

3. 렌더링

4. component 함수 호출 ( Memoize 된 값을 재사용 )

 

UseMemo 의 기본 구문

const value = useMemo(() => {return 계산하는 동작}, [item]);

1. 첫번째 인자인 콜백함수

: Memoization 해줄 값을 계산해서 리턴해주는 함수

2. 두번째 인자인 의존성 배열

: 배열 안에 요소의 값이 업데이트될 때만 콜백함수를 호출해준다.

빈 배열을 줄 때는, 처음 렌더링 될 때만 계산해서 Memoization 해준다.

 

useMemo 는 꼭 필요할 때만 !
- 값을 재사용하기 위해서 따로 값을 메모리에 저장해놓기 때문에, 너무 많이 사용하면 성능 저하가 될 수 있다.

 

useMemo 예제

const hardCalculate = (number) => {
  console.log("어려운 계산!");
  for (let i = 0; i < 999999; i++) {} // 오래 걸리는 계산
  return number + 10000;
}

const easyCalculate = (number) => {
  console.log("쉬운 계산!");
  return number + 1;
}

function App() {
  const [hardNumber, setHardNumber] = useState(1);
  const [easyNumber, setEasyNumber] = useState(1);

  const hardSum = useMemo(() => {
    return hardCalculate(hardNumber)
  },[hardNumber])

  const easySum = easyCalculate(easyNumber)

  return (
    <div>
      <h3>어려운 계산기</h3>
      <input type="number" value={hardNumber} onChange={(e) => setHardNumber(parseInt(e.target.value))} />
      <span> + 10000 = {hardSum}</span>

      <h3>쉬운 계산기</h3>
      <input type="number" value={easyNumber} onChange={(e) => setEasyNumber(parseInt(e.target.value))} />
      <span> + 1 = {easySum}</span>
    </div>
  );
}
- 복잡한 계산을 하는 hardCalculate 함수는 useMemo 의 의존성 배열에 hardNumber 만 수정할 때 실행될 수 있도록 하였다
- easyCalculate 는 쉬운 계산이기때문에 useMemo 를 사용하지 않았다.

쉬운 계산을 할 때는 어려운 계산 함수가 실행되지 않는 모습

 

useEffect 와의 차이

 

useEffect 를 사용할 경우

- 원시 타입일 때

function App() {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(false);

  const location = isKorea ? "한국" : "외국"

  useEffect(() => {
    console.log("useEffect 호출")
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼 먹어요?</h2>
      <input
       type="number"
       value={number}
       onChange={(e) => setNumber(e.target.value)}
       />
       <hr />
       <h2>어느 나라에 있어요?</h2>
       <p>나라 : {location}</p>
       <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  );
}​
- useMemo 와 같이 의존성 배열에 있는 location 의 값이 변경될 때 실행된다.

 

- 객체 타입일 때

function App() {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(false);

  const location = {
    country : isKorea ? "한국" : "외국",
  }

  useEffect(() => {
    console.log("useEffect 호출")
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼 먹어요?</h2>
      <input
       type="number"
       value={number}
       onChange={(e) => setNumber(e.target.value)}
       />
       <hr />
       <h2>어느 나라에 있어요?</h2>
       <p>나라 : {location.country}</p>
       <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  );
}
- useMemo 에 location 의 값이 변하면 실행되도록 했지만, input 의 number 값이 변해도 console.log 가 실행되는 모습이다.

숫자가 업데이트할 때도 콘솔로그에 찍히는 모습

 

원시 타입과 객체 타입

출처 : 별코딩

- 변수에 원시타입을 넣으면, 변수라는 상자에 바로 원시타입이 저장이 되는 반면에

객체 타입은 너무 커서, 어떠한 메모리 상의 공간이 할당되어서 그 메모리 안에 보관이 된다. 그리고 그 변수 안에는 그 메모리의 주소가 담긴다.

 

출처 : 별코딩

- 비교 연산자로 비교를 할 때, 차이점이 들어난다.

- 객체는 메모리의 주소가 서로 다르기 때문에, 다른 값이라고 나오게 된다.

 

객체 타입을 useMemo 로 사용하기

location 이 렌더링이 될 때마다 변수가 초기화되기 때문에, 주소가 계속 바뀐다.
그래서 이 상황을 막기 위해 useMemo 로 memoization 해주도록 한다.
function App() {
  const [number, setNumber] = useState(0);
  const [isKorea, setIsKorea] = useState(false);

  const location = useMemo(() => {
    return {
      country : isKorea ? "한국" : "외국",
    }
  }, [isKorea])

  useEffect(() => {
    console.log("useEffect 호출")
  }, [location])

  return (
    <div>
      <h2>하루에 몇끼 먹어요?</h2>
      <input
       type="number"
       value={number}
       onChange={(e) => setNumber(e.target.value)}
       />
       <hr />
       <h2>어느 나라에 있어요?</h2>
       <p>나라 : {location.country}</p>
       <button onClick={() => setIsKorea(!isKorea)}>비행기 타자</button>
    </div>
  );
}
iskorea 의 값이 변화될때마다 location 의 값이 변경될 수 있도록 해주면, useEffect 를 사용할 때 location 의 값 변화를 인지할 수 있도록 됨.

아까와 다르게 , location 이 변화 될 때만 console.log가 찍히는 모습

 

'React > 이론공부' 카테고리의 다른 글

[React Hooks] useReducer  (0) 2023.01.25
[React Hooks] useCallback  (0) 2023.01.25
[React Hooks] useContext & Context  (0) 2023.01.24
[React Hooks] useRef  (0) 2023.01.24
[React Hooks] useEffect  (0) 2023.01.24