useMemo, useCallback

Yeom Jae Seon·2021년 1월 5일
0

React

목록 보기
1/3
post-thumbnail

useMemo


useState, useEffect, useRef만 알지말고 useMemo, useCallback도 알아보자.

  • const memoizedValue = useMemo(() => expensiveWork(num), [num]) 이런식으로 useMemo는 두번째 인자에오는 의존성 배열안의 값 num이 변할때만 expensiveWork, 즉 어떠한 계산을 다시하고, num이 변하지 않으면 어떠한 계산에 대한 결과를 기억했다가 (어떠한 값이다) 재사용하는 Hook 메소드이다.
  • 즉, 같은 값이 들어오면 불필요하게 다시 계산하지않아 최적화를 도모할수있는 방법중 하나이다.

useCallback


  • const memoizedCallback = useCallback(func, [deps])로 사용하며 useMemo와 같이 두번째인자인 deps가 변경되지 않으면 함수를 기억하고 deps가 변경되면 다시 새로운 reference를 받는다.

  • 이 useCallback도 불필요하게 다시 함수가 재정의되는걸 막아 최적화를 도와준다.
    useCallback은 특히 자식컴포넌트가 pureComponent로
    shoudComponentUpdate가 구현되어 있을 때 사용이 유용하다.

  • 바로 예시를 봐보자.

예시 코드

//App.js
import React, { useState, useMemo, useCallback } from "react";
import Child from "./components/Child";

const translateCountry = (country) => {
  console.log("나라번역중..");
  switch (country) {
    case "korea":
      return "한국";
    case "japan":
      return "일본";
    case "usa":
      return "미국";
    case "china":
      return "중국";
    default:
      return "어딘지 잘모르겠어요..";
  }
};
const translateCity = (city) => {
  console.log("도시 번역중..");
  switch (city) {
    case "seoul":
      return "서울";
    case "tokyo":
      return "도쿄";
    case "washington":
      return "워싱턴";
    case "beijing":
      return "북경";
    default:
      return "어딘지 잘모르겠어요..";
  }
};

const App = () => {
  const [country, setCountry] = useState("");
  const [city, setCity] = useState("");

  // useMemo 사용 x
  const myCountry = translateCountry(country);
  const myCity = translateCity(city);

  // useMemo 사용 0
  // const myCountry = useMemo(() => translateCountry(country), [country]);
  // const myCity = useMemo(() => translateCity(city), [city]);

  // useCallback 사용 x
  const onChangeHandler = (e) => {
    if (e.target.id === "country") setCountry(e.target.value);
    else setCity(e.target.value);
  };
  // useCallback 사용 0
  // const onChangeHandler = useCallback((e) => {
  //   if (e.target.id === "country") setCountry(e.target.value);
  //   else setCity(e.target.value);
  // }, []);

  return (
    <>
      <div>
        <label>
          What is your country ?
          <input id="country" value={country} onChange={onChangeHandler} />
        </label>
      </div>
      <label>
        What is your city ?
        <input value={city} onChange={onChangeHandler} />
      </label>
      <div className="display">
        <p>나의 나라는 {myCountry}</p>
        <p>나의 도시는 {myCity}</p>
      </div>
      <Child func={onChangeHandler} />
    </>
  );
};

export default App;
//Child.js
// props로 전달되는 onChangeHandler함수가
// 메모이제이션잘되는지 확인하기위한 컴포넌트
import React, { memo } from "react";

const Child = memo(() => {
  console.log("Child rendered");
  return <div></div>;
});

export default Child;
  • 단순히 Child컴포넌트는 props로 onChangeHandler함수만 받고(reference) memo로 최적화가 되어있다.
  • 즉, useCallback을 사용하면 onChangeHandler함수는 메모리에 App컴포넌트가 마운트될때만 메모리에 reference가 할당되는지를 확인하기 위함이다.

useCallback과 useMemo의 남용은 좋지않다. - 최적화를 하려고 썼는데 오히려 메모이제이션되는 비용이 더 비쌀수도 있다.
나도 불필요한 컴포넌트의 리랜더링을 막으려고 useCallback을 남용했다.
직접 브라우저위에서 성능 테스트를 하지도 않은채..
무조건적으로 기술을 받기보단 그 전에 한번더 생각해보는 계기가 되었다.

0개의 댓글