JS Library/React

useMemo 를 사용하여 연산한 값 재사용하기

원2 2022. 5. 24. 17:29
728x90
반응형

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

 

App 컴포넌트에서 아래와 같이 countActiveUsers 라는 함수를 만들어서, active 값이 true 인 사용자의 수를 세어서 화면에 렌더링 해보자

 

App.js

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

function App() {

    function countActiveUsers(users) {
        console.log("active 값이 ture 인 유저의 수를 센는중...");
        return users.filter(user => user.active).length;
    }


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

    const {username, email} = inputs;

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

    // useState 를 사용하여 컴포넌트의 상태로 관리
    const [users, setUsers] = useState([
        {
            id: 1,
            username: 'velopert',
            email: 'public.velopert@gmail.com',
            active: true
        },
        {
            id: 2,
            username: 'tester',
            email: 'tester@example.com',
            active: false
        },
        {
            id: 3,
            username: 'liz',
            email: 'liz@example.com',
            active: false
        }
    ]);


    const nextId = useRef(4);
    const onCreate = () => {
        // 나중에 구현 할 배열에 항목 추가하는 로직
        // ...

        const user = {
            id: nextId.current,
            username,
            email
        };
        // concat 함수
        setUsers(users.concat(user));
        
        // spread 함수
        // setUsers([
        //     //spread 문법
        //     ...users,user
        // ]);

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

        nextId.current += 1;
    };

    const onRemove = id => {
    //    user.id 가 파라미터로 일치하지 않는 우너소만 추출해서 새로운 배열을 만듬
    //    = user.id 가 id 인 것을 제거함
        setUsers(users.filter(user => user.id !== id));
    }


    const onToggle = id => {
                setUsers(
            users.map(user =>
                user.id === id ? {...user, active: !user.active} : user
            )
        );
    };
    const count = countActiveUsers(users);

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


export default App;

** 참고

const count 함수는 우리가 useState 로 지정해둔 객체들 보다 먼저 생성하면 안됌.

당연히 렌더링 할 객체가 없으니 에러뜸ㅇㅇ

 

콘솔에 active 값이 ture 인 유저의 수를 세는중 ... 이 출력된다 오타 ㅈㅅ // 계정들을 클릭할 때마다 활성 사용자수가 업데이트 된다

 

countActiveUsers 함수에서 콘솔에 메시지를 출력하도록 한 이유는, 이 함수가 호출 될 때마다 알수 있게 하기 위함!

 


근데, 여기서 발생하는 한가지 문제

input 의 값을 바꿀때도 countActiveUsers 함수가 호출됨;

 

input 에 값이 변경될 때 마다 호출됨..

활성 사용자 수를 세는 건 users 에 변화가 있을때만 세야되는건데 input 값이 바뀔 때에도 컴포넌트가 리렌더링 되므로 자원이 낭비되는중

 

이럴때 useMemo Hook 함수를 사용하여 성능을 최적화 시켜보자

 


App.js

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

function App() {

    function countActiveUsers(users) {
        console.log("active 값이 ture 인 유저의 수를 센는중...");
        return users.filter(user => user.active).length;
    }


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

    const {username, email} = inputs;

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

    // useState 를 사용하여 컴포넌트의 상태로 관리
    const [users, setUsers] = useState([
        {
            id: 1,
            username: 'velopert',
            email: 'public.velopert@gmail.com',
            active: true
        },
        {
            id: 2,
            username: 'tester',
            email: 'tester@example.com',
            active: false
        },
        {
            id: 3,
            username: 'liz',
            email: 'liz@example.com',
            active: false
        }
    ]);


    const nextId = useRef(4);
    const onCreate = () => {
        // 나중에 구현 할 배열에 항목 추가하는 로직
        // ...

        const user = {
            id: nextId.current,
            username,
            email
        };
        // concat 함수
        setUsers(users.concat(user));
        
        // spread 함수
        // setUsers([
        //     //spread 문법
        //     ...users,user
        // ]);

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

        nextId.current += 1;
    };

    const onRemove = id => {
    //    user.id 가 파라미터로 일치하지 않는 우너소만 추출해서 새로운 배열을 만듬
    //    = user.id 가 id 인 것을 제거함
        setUsers(users.filter(user => user.id !== id));
    }


    const onToggle = id => {
                setUsers(
            users.map(user =>
                user.id === id ? {...user, active: !user.active} : user
            )
        );
    };
    const count = useMemo(() => countActiveUsers(users), [users]);

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


export default App;

 

useMemo 의 첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를 넣어주면 되고

두번째 파라미터에는 deps 배열을 넣어주면 됨

deps 배열의 내용이 바뀌면 등록한 함수를 호출해서 값을 연산하고 바뀌지 않으면 이전에 연산한 값을 재사용함.

 

아래 object은 신경쓰지말자 input 값을 변경해줘도 countActiveUsers 함수는 동작하지 않고, 해당 계정의 active 값만 바뀔 때 동작한다.

https://react.vlpt.us/basic/17-useMemo.html

728x90
반응형