useMemo 에 대해서

이동명·2023년 6월 23일
0
post-thumbnail

1.useMemo란?

useMemo 는 리액트에서 컴포넌트의 성능을 최적화 하는데 사용되는 훅이다.

useMemo 에서 memo는 memoization을 뜻하는데 이는 그대로 해석하면 ‘메모리에 넣기’라는 의미이며 컴퓨터 프로그램이 동일한 계산을 반복해야 할 때, 이전에 계산한 값을 메모리에 저장함으로써 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술이다.

쉽게 말해 동일한 값을 반환하는 함수를 반복적으로 호출해야한다면 처음 값을 계산할 때 해당 값을 메모리에 저장해 필요할 때마다 다시 계산하지 않고 메모리에서 꺼내서 재사용하는 것이다.

리액트에서 함수형 컴포넌트는 렌더링 => 컴포넌트 함수 호출 => 모든 내부 변수 초기화의 순서를 거친다.

2.useMemo 예제

// App.js

function App() {
  const [listTitle, setListTitle] = useState('My List');

  const changeTitleHandler = useCallback(() => {
    setListTitle('New Title');
  }, []);

  const listItems = [5, 3, 1, 10, 9];

  return (
      <div className="app">
        <DemoList title={listTitle} items={listItems} />
        <Button onClick={changeTitleHandler}>Change List Title</Button>
      </div>
  );
}

export default App;
// Demolist.js

const DemoList = (props) => {
  const { items } = props;

  const sortedList = () => {
    console.log('Items sorted');
    return items.sort((a, b) => a - b);
  };

  console.log('DemoList RUNNING');

  return (
      <div className={classes.list}>
        <h2>{props.title}</h2>
        <ul>
          {sortedList().map((item) => (
              <li key={item}>{item}</li>
          ))}
        </ul>
      </div>
  );
};

export default React.memo(DemoList);

위의 App.js 에서 button 을 클릭하면 부모 컴포넌트의 상태 변경으로 인해 자식 컴포넌트로 리 렌더링을 하게 된다. 그렇게 되었을 경우 DemoList.js 가 실행될 때 props로 전송되는 listItems 을 매번 솔팅을 하게 되면서 불 필요한 작업을 계속 진행하게 된다. 따라서


const DemoList = (props) => {
  const { items } = props;

  const sortedList = useMemo(() => {
    console.log('Items sorted');
    return items.sort((a, b) => a - b);
  }, [items]);
  
  
  console.log('DemoList RUNNING');

  return (
      <div className={classes.list}>
        <h2>{props.title}</h2>
        <ul>
          {sortedList.map((item) => (
              <li key={item}>{item}</li>
          ))}
        </ul>
      </div>
  );
};

export default React.memo(DemoList);

useMemo 를 사용해서 이전에 계산한 값을 메모리에 넣어 불필요한 작업을 최소화 하였다.

하지만 이렇게 작업을 하여도 불필요한 sorting 은 계속 해주고 있다. 왜일까 ?

이유는 의존성에서 추가해준 items 가 계속 바뀌고 있기 때문이었다.

하지만 App.js 에서 items 는 하드코딩을 해놓아서 바뀔일이 없는데 왜 그럴까 ?

이유는 리액트의 구동방식 자체가 간단히 이야기 하면 최근 스냅샷과 변경사항을 비교해서 변경사항이 있다면 업데이트 하는식으로 되어있는데

자바스크립트의 참조타입은 간접 메모리 방식을 참조하고 있기 때문에 비교가 불가능해서 그런것이었다.

function App() {
  const [listTitle, setListTitle] = useState('My List');

  const changeTitleHandler = useCallback(() => {
    setListTitle('New Title');
  }, []);

  const listItems = useMemo(() => [5, 3, 1, 10, 9], []);

  return (
      <div className="app">
        <DemoList title={listTitle} items={listItems} />
        <Button onClick={changeTitleHandler}>Change List Title</Button>
      </div>
  );
}

export default App;

 useMemo 를 사용하면 렌더링 => 컴포넌트 함수 호출 => memoize된 함수 재사용하는 순서를 거친다. 따라서 listItems 를 다시 호출하지 않고 메모리에 저장한 값으로 쓰면서 참조타입 이슈도 해결이 되는 것 같다. 지금은 추상적인 개념만 잡혀 필기가 쉽지 않은데 추후 개념이 더 잡히면 수정 하도록 해야할 것 같다.

profile
Web Developer

0개의 댓글