05
29

ㅇ리소스 누수를 막아봅시다

1. useMemo?

  • input이나 state 값이 바뀌는 경우 react는 컴포넌트들을 리렌더링 한다. 
  • 이때, 변화가 없는 값을 계산하는 함수일 경우 다시 호출 될 필요가 없다.
  • 이럴 때, 최적화를 위해 사용되는 것이 useMemo이다.
  • 진정한 뜻은 'memoization'에서 온 것으로, 메모리에 이전 값을 저장해서 변경이 없는 값이면 불필요하게 계산을 하지 않게 된다. 

2. 예시

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [num, setNum] = useState(100);
  const [value, setValue] = useState("");

  const getNum = () => {
    console.log("num : ", num);
    return num;
  };

  const item = getNum();

  return (
    <div className="App">
      <h1>num : {item}</h1>
      <button onClick={() => setNum((prev) => ++prev)}>Add num</button>
      <h1>value : {value}</h1>
      <input onChange={(e) => setValue(e.target.value)} />
    </div>
  );
}
  • 매우 간단한 코드이다. 당근, input의 state인 value가 바뀌면 전혀 관계없는 num를 알려주는 getNum도 호출되므로, num은 바뀌지 않았지만 불필요하게 함수가 호출된다.

리소스가 줄줄센다

  • 하지만 useMemo를 사용해서 바꿔줄 수 있다.
import "./styles.css";
import { useState, useMemo } from "react";

export default function App() {
  const [num, setNum] = useState(100);
  const [value, setValue] = useState("");

  const getNum = () => {
    console.log("num : ", num);
    return num;
  };

  const item = useMemo(() => getNum(), [num]);

  return (
    <div className="App">
      <h1>num : {item}</h1>
      <button onClick={() => setNum((prev) => ++prev)}>Add num</button>
      <h1>value : {value}</h1>
      <input onChange={(e) => setValue(e.target.value)} />
    </div>
  );
}
  • useEffect를 사용할 때 처럼, num이 바뀔 때만 getNum을 호출하자. 그럼 value가 바뀔 때는 getNum은 호출되지 않는다.

땜빵전문

3. 실전팁

  • 각종 상황에 사용할 수 있지만, 가장 유용하다고 생각하는 부분은 아래 코드처럼 불필요한 컴포넌트 렌더링 자체를 피할 수 있다.
  • 슬라이드 메뉴, 파일을 넘나들지만 state로 관리되면 안되는 데이터들도 useMemo로 처리할 수 있다.
import { useMemo  } from 'react';

function Analysis() {
  const { path } = useParams();

  const content = useMemo(() => {
    switch (path) {
      case 'home':
        return <Home />;
      case 'login':
        return <Login />;
      case 'intro':
        return <Intro />;
      case 'Info':
        return <Info />;
      default:
        return null;
    }
  }, [path]);

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

export default App;

4. 주의사항

  • useMemo의 사용이 항상 옳지는 않다. 리렌더링을 방지하는 용도로 사용하는 것이 아니라, '리소스'를 절약해 주는 것에 의의가 있다.
  • 복잡한 함수가 아닐경우, 함수를 한 번 더 호출하는 것이 나은 경우도 있다. useMemo를 남발하면 코드 유지보수가 어려워진다.
  • 그리고 결국 메모리를 사용하는 작업이고, 결과가 바뀔 때마다 계산을 시도는 하기 때문에 너무 변동이 많은 곳에 사용하면 성능이 되려 떨어지게 될 수 도 있다.
COMMENT