[ 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
복사