본문 바로가기

오픈소스/노드

[Node] React 정리(11) - useMemo를 사용하여 연산한 값 재사용하기

리액트로 프로젝트를 생성하여 개발하는 과정 중 리액트의 필수 문법 및 기초적인 부분, 심화 과정 등을 정리한 문서입니다. 정리한 부분에는 제가 이해하는 관점에서만 정리를 하였기 때문에 초점은 보여주는 형식이 아닌 제가 필요할 때 사용하려는 목적이 담겨져 있습니다. 컴포넌트에서 useMemo를 이용하여 연산한 값을 재사용 하는 예제를 담았습니다. 

 

 진부한 예제이지만 useMemo의 기초와 사용법 에 대해 배워보도록 합시다.

 

 

# Contents


  • 사용하는 이유
  • useMemo 기초와 사용법

 

 

# 사용하는 이유


이번에는 성능 최적화를 위하여 연산된 값을 useMemo라는 Hook 을 사용하여 재사용하는 방법을 알아보도록 하겠습니다. App 컴포넌트에서 다음과 같이 countActiveUsers 라는 함수를 만들어서, active 값이 true 인 사용자의 수를 세어서 화면에 렌더링을 해보세요.

 

먼저 App.js 코드는 아래와 같습니다.

 

import "./App.css";
import react, { useRef, useState, useMemo, useEffect } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";

function App() {
    const [input, setInputs] = useState({
        name: "",
        email: "",
    });

    const { name, email } = input;

    const [users, setUsers] = useState([
        { id: 0, name: "John", email: "john@gmail.com", active: true },
        { id: 1, name: "Smith", email: "smith@gmail.com", active: false },
        { id: 2, name: "Park", email: "park@gmail.com", active: false },
        { id: 3, name: "Kim", email: "kim@gmail.com", active: false },
    ]);
    var nextId = useRef(5);

    var count = countActiveUsers(users);

    return (
        <div>
            <CreateUser name={name} email={email} onChange={onChange} onClick={onClick} />
            <UserList users={users} onToggle={onToggle} onDelete={onDelete} />
            <div>활성화된 사용자 수 : {count}</div>
        </div>
    );

    function onChange(e) {
        var { name, value } = e.target;
        setInputs({ ...input, [name]: value });
    }

    function onClick() {
        setUsers([...users, { id: nextId.current++, name, email, active: false }]);
    }

    function onToggle(userId) {
        setUsers(
            users.map((user) => {
                return userId === user.id ? { ...user, active: true } : user;
            })
        );
    }

    function onDelete(userId) {
        var newArr = [];
        users.map((user) => {
            return user.id !== userId ? newArr.push(user) : "";
        });

        setUsers([...newArr]);
    }

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

export default App;

 

 22번째 줄에서 countActiveUser 함수를 호출하도록 하였습니다. 이렇게 수행하면 우리는 이 countActiveUsers가 언제 실행이 되는 지 디버깅 할 수 있습니다.  다음 함수를 호출하면 아래와 같은 콘솔창에 로그가 나타나게 됩니다.

 

 

 

 하지만 input 의 값을 수정할 때도 함수를 호출하는 것을 아래와 같이 확인할 수 있었습니다.

 

 

 

본 예제에서는 이러한 문제를 최적화 하기 위한 useMemo() Hook을 이용하여 처리합니다.

 

 

# useMemo 기초와 사용법


 useMemo를 사용하기 위해서는 다음과 같은 구문을 사용해야 합니다.

 

import react, { useMemo } from "react";

 

UseMemo는 다음과 같습니다.

  • 성능을 최적화할 때 사용한다.
  • memo는 memorized의 약자이다.
  • 첫번째 인수에는 함수, 두번째 인수에는 배열을 넣어주면 된다.
  • 두번째 인수에 넣어준 배열의 값이 바뀔때만 함수가 실행된다.
  • 그렇지 않다면 이전의 값을 재사용한다.

 

구문은 다음과 같습니다.

 

useMemo(() => {실행할 함수}, 변화감지변수);

 

아래 코드를 통해 useMemo를 확인해보세요. 

 

import "./App.css";
import react, { useRef, useState, useMemo, useEffect } from "react";
import UserList from "./UserList.js";
import CreateUser from "./CreateUser";

function App() {
    const [input, setInputs] = useState({
        name: "",
        email: "",
    });

    const { name, email } = input;

    const [users, setUsers] = useState([
        { id: 0, name: "John", email: "john@gmail.com", active: true },
        { id: 1, name: "Smith", email: "smith@gmail.com", active: false },
        { id: 2, name: "Park", email: "park@gmail.com", active: false },
        { id: 3, name: "Kim", email: "kim@gmail.com", active: false },
    ]);
    var nextId = useRef(5);

    var count = useMemo(() => countActiveUsers(users), users);

    return (
        <div>
            <CreateUser name={name} email={email} onChange={onChange} onClick={onClick} />
            <UserList users={users} onToggle={onToggle} onDelete={onDelete} />
            <div>활성화된 사용자 수 : {count}</div>
        </div>
    );

    function onChange(e) {
        var { name, value } = e.target;
        setInputs({ ...input, [name]: value });
    }

    function onClick() {
        setUsers([...users, { id: nextId.current++, name, email, active: false }]);
    }

    function onToggle(userId) {
        setUsers(
            users.map((user) => {
                return userId === user.id ? { ...user, active: true } : user;
            })
        );
    }

    function onDelete(userId) {
        var newArr = [];
        users.map((user) => {
            return user.id !== userId ? newArr.push(user) : "";
        });

        setUsers([...newArr]);
    }

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

export default App;