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

작업
진행 상태
완료
진행일시
2021/11/27
학습자

[ useMemo ]

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

[ App.js ]

import React, { useRef, useState } from 'react'; import UserList from './UserList'; import CreateUser from './CreateUser'; function countActiveUsers(users) { console.log('활성 사용자 수를 세는중...'); return users.filter(user => user.active).length; } function App() { const [inputs, setInputs] = useState({ username: '', email: '' }); const { username, email } = inputs; const onChange = e => { const { name, value } = e.target; setInputs({ ...inputs, [name]: value }); }; 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 }; setUsers(users.concat(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;
JavaScript
복사
countActiveUsers 함수에서 콘솔에 메시지를 출력하도록 한 이유는, 이 함수가 호출될때마다 우리가 알수있게 하기 위함입니다.

[주의 할 점]

활성 사용자 수를 세는건, users 에 변화가 있을때만 세야되는건데, input 값이 바뀔 때에도 컴포넌트가 리렌더링 되므로 이렇게 불필요할때에도 호출하여서 자원이 낭비되고 있습니다. 이러한 상황에는 useMemo 라는 Hook 함수를 사용하면 성능을 최적화 할 수 있습니다. Memo 는 "memoized" 를 의미하는데, 이는, 이전에 계산 한 값을 재사용한다는 의미를 가지고 있습니다.
import React, {useRef, useState, useMemo}from 'react'; // import React from 'react'; import './App.css' // import InputSample2 from './InputSample2'; import UserList from './UserList'; import CreateUser from './CreateUser'; // []의 의미는 key값으로 쓰겠다는 의미입니다. // [name] 이 username과 email 두가지의 경우가 있는데, // onChange라는 하나의 함수로 여러값을 저장하기 위해서 사용한것으로 보여집니다. // [e.target.name] : e.target.value 이런식으로 state에 저장을하면 input마다 // 다른 함수를 사용하지 않고 여러개 input값을 저장할 수 있습니다. // username:e.target.value, email: e.target.value // 이렇게 dynamic하게 key값이 들어갑니다^^ //useMemo를 사용하여 연산한 값 재사용 //App 컴포넌트에서 다음과 같이 countActiveUsers 라는 함수를 만들어서, active 값이 true 인 사용자의 수를 세어서 화면에 렌더링을 해보세요. function countActiveUsers(users) { console.log('활성 사용자 수를 세는중 ...'); return users.filter(user => user.active).length; } function App() { const [Inputs, setInputs] = useState({ username : '', email : '', id : '' }); const {username, email, id} = Inputs; const onChange = (e) => { const {name, value} = e.target; setInputs({ ...Inputs, [name] : value }) } 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 }, ]); //다음값 id지정 const nextId = useRef(4); //새롭게 등록할 때 const onCreate = () => { const user = { id : nextId.current, username : username, email : email }; setUsers([...users, user]); setInputs({ username : '', email : '' }) nextId.current += 1; } //삭제하기위해서는 각 id를 알아야한다 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 onUpdate = () => { setUsers ( users.map(user => user.id === id ? {...user, username: username, email : email} : user) ); setInputs({ username : '', email : '', id : '' }) } // 활성 사용자 수를 세는건, users 에 변화가 있을때만 세야되는건데, //input 값이 바뀔 때에도 컴포넌트가 리렌더링 되므로 이렇게 불필요할때에도 호출하여서 자원이 낭비되고 있습니다. // 이러한 상황에는 useMemo 라는 Hook 함수를 사용하면 성능을 최적화 할 수 있습니다. // Memo 는 "memoized" 를 의미하는데, 이는, 이전에 계산 한 값을 재사용한다는 의미를 가지고 있습니다. const count = useMemo(() => countActiveUsers(users),[users]); const onModify = (user) => { setInputs({ username : user.username, email : user.email, id : user.id }) } return ( <> <CreateUser username = {username} email = {email} onChange = {onChange} onCreate = {onCreate} onUpdate = {onUpdate} /> <UserList users={users} onRemove={onRemove} onToggle={onToggle} onModify={onModify}/> <div>활성 사용자 수 : {count}</div> </> ); // return ( // <InputSample2 /> // ) } export default App;
JavaScript
복사