useMemo Example(Hook)

 

성능 최적화를 위하여 연산된 값을 재사용하는 useMemo예제

send me email if you have any questions.


사용자 수 count(성능 최적화X)

import React, { useRef, useState } from 'react';
import UserList from './components/UserList';
import CreateUser from './components/CreateUser';

function countUsers(users){
  console.log("counting users...");

  return users.length;
}

function App() {
  const [users, setUsers] = useState([
    {
      id: 1,
      username: '임준호',
      phonenumber: '010-0000-0000'
    },
    {
      id: 2,
      username: 'testuser1',
      phonenumber: '010-1234-1234'
    },
    {
      id: 3,
      username: 'testuser2',
      phonenumber: '010-2222-4444'
    }
  ]);

  const [inputs, setInputs] = useState({
    username: '',
    phonenumber: ''
  });
  const { username, phonenumber } = inputs;

  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };

  const nextId = useRef(4);

  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      phonenumber
    };
    setUsers(users.concat(user))

    setInputs({
      username: '',
      phonenumber: ''
    });

    nextId.current += 1;
  };

  const onRemove = id => {
    setUsers(users.filter(user => user.id !== id));
  };

  const onUpdate = id => {
    setUsers(
      users.map(user =>
        user.id === id ?
          { id: nextId.current, username: username, phonenumber: phonenumber }
          : user
      )
    );

    setInputs({
      username: '',
      phonenumber: ''
    });

    nextId.current += 1;
  };

  const count = countUsers(users);

  return (
    <div>
      <CreateUser
        username={username}
        phonenumber={phonenumber}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onUpdate={onUpdate} />
      <div>사용자 수 : {count}</div>
    </div>
  );
};

export default App;

App.js
랜더링된 유저의 수를 세는 countUsers구현

그림1 예제 실행결과

Console에 출력된 log를 보면 input의 값이 바뀔때에도 컴포넌트가 리렌더링 되므로 countUsers가 실행되는것을 볼 수 있다.
users의 변화가 있을 때만 countUsers가 호출된다면 기존에비해 효율성이 증대될 것이다.

참고로 React 문서에 따르면, log가 2번씩 찍히는 것은 React에서 의도된 기능이라고 한다.
useState를 사용한 함수형 컴포넌트가 두 번 실행되는 이유?
StrictMode에서 실행되는 이 기능은 사이드 이펙트를 발견할 수 있도록 도와준다.

What is Strict Mode?
index.js에서 볼 수 있는 이 기능은 애플리케이션 내의 잠재적인 문제를 알아내기 위한 도구라고 한다.
개발모드에서만 활성화 되기 때문에, 프로덕션 빌드에는 영향을 끼치지 않는다.

사용자 수 count(성능 최적화)

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

function countUsers(users){
  console.log("counting users...");

  return users.length;
}

function App() {
  const [users, setUsers] = useState([
    {
      id: 1,
      username: '임준호',
      phonenumber: '010-0000-0000'
    },
    {
      id: 2,
      username: 'testuser1',
      phonenumber: '010-1234-1234'
    },
    {
      id: 3,
      username: 'testuser2',
      phonenumber: '010-2222-4444'
    }
  ]);

  const [inputs, setInputs] = useState({
    username: '',
    phonenumber: ''
  });
  const { username, phonenumber } = inputs;

  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };

  const nextId = useRef(4);

  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      phonenumber
    };
    setUsers(users.concat(user))

    setInputs({
      username: '',
      phonenumber: ''
    });

    nextId.current += 1;
  };

  const onRemove = id => {
    setUsers(users.filter(user => user.id !== id));
  };

  const onUpdate = id => {
    setUsers(
      users.map(user =>
        user.id === id ?
          { id: nextId.current, username: username, phonenumber: phonenumber }
          : user
      )
    );

    setInputs({
      username: '',
      phonenumber: ''
    });

    nextId.current += 1;
  };

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

  return (
    <div>
      <CreateUser
        username={username}
        phonenumber={phonenumber}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} onUpdate={onUpdate} />
      <div>사용자 수 : {count}</div>
    </div>
  );
};

export default App;

App.js
useMemo 의 첫 번째 파라미터에는 함수를, 두 번째 파라미터에는 deps 배열을 전달한다.
deps 배열 안의 값이 바뀌면 첫 번째 파라미터로 전달한 함수를 호출해서 값을 연산하고, 값이 바뀌지 않았다면 이전에 연산한 값을 재사용한다.

그림1
예제 실행결과