useMemo를 사용한 연산한 값 재사용

9819 단어 useMemohookhook

성능 최적화를 위하여 연산된 값을 useMemo 라는 hook 을 사용하여 재사용하는 방법을 알아보도록 하자.

App 컴포넌트에서 다음과 같이 countActiveUsers 라는 함수를 만들어서 active 값이 true 인 사용자의 수를 세어서 화면에 렌더링이 되도록 했다.

import React, {useState, useEffect, useRef, useMemo} from 'react';
import CreateUser from "./Components/CreateUser";
import UserList from "./Components/UserList";

function countActiveUsers(users) {
  console.log('활성 사용자 수를 세는중...');
  return users.filter(user => user.active).length;
}

function App() {
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  
  ...
  
  const count = countActiveUsers(users);
  
  return(
    <div>
      <CreateUser username={username} email={email} onChange={onChange} onCreate={onCreate} onUpdate={onUpdate}/>
      <UserList users={users} onRemove={onRemove} onToggle={onToggle} onModify={onModify}/>
      <div>활성사용자 수: {count}</div>
    </div>
  )
}

이 상태에서는 성능적 문제가 하나 발생한다. 바로 input 의 값을 바꿀때에도 countActiveUsers 함수가 호출된다는 것이다.

활성 사용자 수를 세는건, users 에 변화가 있을 때만 세면된다. 하지만 현재는 input 값이 바뀔 때에도 컴포넌트가 리렌더링 되므로 이렇게 불필요할때에도 함수가 호출되어 자원이 낭비되고 있다.

+ input 값을 바꿀 때 countActiveUsers 함수가 호출되는 이유
예를 들어 계정명을 입력한다고 하자. CreateUser 컴포넌트의 username 의 속성(props)가 바뀌게 되는데, 이 값은 원래 App 컴포넌트의 state이다. 결국 input에 입력하는 행위는 App 컴포넌트의 state를 바꾸는 행위이다. 따라서 App의 state가 변경되었으니 App 컴포넌트가 다시 렌더링되면서 App 컴포넌트 내에 있는 count 선언문 const count = countActiveUsers(users);이 실행되고, 따라서 countActiveUsers 함수가 호출되는 것이다.

이러한 상황에서는 useMemo 라는 hook 을 사용하여 성능을 최적화 할 수 있다. Memo 는 "memoized" 를 의미하는데, 이는 이전에 계산한 값을 재사용한다는 의미를 가지고 있다.

이 부분을

const count = countActiveUsers(users);

이렇게 바꾸면 된다.

const count = useMemo(() => countActiveUsers(users), [users]);

useMemo 의 첫 번째 인자에는 어떻게 연산할지 정의하는 함수를 넣어주면 되고 두 번째 인자에는 deps 배열을 넣어주면 된다. 이 배열안에 넣은 내용이 바뀌면, 우리가 등록한 함수를 호출해서 값을 연산해주고, 만약에 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용하게 된다.

처음에 useMemo 를 알았을 때 useEffect 와 차이점이 뭐지? 라고 생각했다. 그래서 useEffect로 구현하려고 했었다.

var count = countActiveUsers(users);

   useEffect(()=>{
     count = countActiveUsers(users);
   },[users])

첫 번째 시도에서 useEffect 을 이용해 users의 값이 바뀔때만 count의 값이 변경되도록 했으나, 결국 App컴포넌트가 렌더링 될때 count 선언문도 같이 실행되기 때문에 소용없다는 걸 알았다.

   useEffect(()=>{
     const count = countActiveUsers(users);
   },[users])

두 번째 시도에서는 useEffect 안에 count변수를 정의해서 App컴포넌트가 렌더링될때 선언이 실행되지 않도록 했다. 하지만 결국 useEffect 에서 정의된 지역변수이기 때문에 return 문에서 count값을 사용할 수 없었다.

따라서 결국 useMemo 를 사용할 수 밖에 없었지만 이론적인 명쾌한 답을 얻지는 못하였다. 조금 더 알아본 후 관련 내용을 추가하도록 하겠다.

좋은 웹페이지 즐겨찾기