[react] useMemo , useCallback , React.memo를 통한 성능 최적화
https://react.vlpt.us/basic/17-useMemo.html
17. useMemo 를 사용하여 연산한 값 재사용하기 · GitBook
17. useMemo 를 사용하여 연산한 값 재사용하기 이번에는 성능 최적화를 위하여 연산된 값을 useMemo라는 Hook 을 사용하여 재사용하는 방법을 알아보도록 하겠습니다. App 컴포넌트에서 다음과 같이 co
react.vlpt.us
useMemo
- 성능 최적화를 할 수 있다. 연산된 값을 재사용할 수 있게 만들어준다.
App.js 추가
function countActiveUsers(users){
console.log('활성 사용자를 세는 중!');
return users.filter(user=>user.active).length;
}
function App(){
const count = countAvtiveUsers(users);
return(
<div> 활성 사용자 수 : {count} </div>
)
}
코드작성을 완료한 뒤 콘솔창을 보면
활성 사용자수가 바뀔때마다 콘솔이 찍힌다 !
근데 문제는 input에 새로운걸 작성할때마다 마차나지로 콘솔이 찍혀버린다.
" 활성 사용자 수를 세는건, users 에 변화가 있을때만 세야되는건데, input 값이 바뀔 때에도 컴포넌트가 리렌더링 되므로 이렇게 불필요할때에도 호출하여서 자원이 낭비되고 있습니다. "
-> 저 함수가 호출되는거는 app 컴포넌트가 리렌더링 될 때인데,
input 값이 입력될 때마다 app 컴포넌트가 리렌더링 되니까 이때 계속 함수가 호출되는것이다.
useMemo를 이용해서 이전 계산 된 값을 재사용할수있다
app 컴포넌트의 count 변수를 바꿔서 써준다
const count = useMemo(()=> countActiveUsers(users),[users]);
1. 첫번째 파라미터에는 어떻게 연산할 지를 정의해주는 함수가 들어간다.
2. 두번째 파라미터에는 deps 배열이 들어간다.
3. deps 안에 넣은 내용이 바뀌면, 첫번째 파라미터에 등록된 함수를 호출해서 값을 연산해주고
만약에 deps 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용 한다.
따라서 성능 최적화가 되는것이다.
useCallbak
- useMemo는 특정 결과값을 재사용할때 쓰고 , useCallback은 특정 함수를 재사용할 때 쓴다.
onChange , onCreate , onRemove , onToggle 코드를 바꿔준다
const onChange = useCallback(
e =>{
const {name,value} = e.target;
setInputs({
...inputs,
[name]:value
});
},
[inputs]
);
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [users, username, email]);
const onRemove = useCallback(
id => {
setUsers(users.filter(user => user.id !== id));
},
[users]
);
const onToggle = useCallback(
id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
},
[users]
);
React Developer Tools
Adds React debugging tools to the Chrome Developer Tools. Created from revision e28a0db22 on 1/24/2022.
chrome.google.com
확장 프로그램에서
react Developer Tools을 깔아서 보면 톱니바퀴 설정 눌러서 highlight update에 체크 표시를 해준다.
그러면 특정 컴포넌트가 리렌더링 될때 하이라이트 표시를 해준다.
useMemo 나 useCallback을 이용해서 최적화를 진행한 이후에
해당 화면을 조작해보면서
상태를 바꿔보면 어떤 부분들이 리렌더링 되는지 알 수 있다.
React.memo 를 사용한 컴포넌트 리렌더링 방지
- React.memo 함수를 이용하면, 컴포넌트의 props가 바뀌지 않았다면 리렌더링을 하지 않도록 방지해준다.
따라서 컴포넌트 리렌더링 성능 최적화를 해줄 수 있다.
- 리렌더링이 필요한 상황에만 리렌더링 되도록
* 사용법
감싸주면 된다.
export default 되는 부분에서 감싸주거나,
컴포넌트를 한 페이지에 여러개 써서 export default 하지 않았을 때는 ,
그냥 해당 컴포넌트를 선언해주는 부분에서 감싸주면 된다.
예를 들어
UserList.js 에서 User 컴포넌트와 UserList 컴포넌트에 React.memo를 적용하는 방법을 보면
import React from 'react';
const User = React.memo(function User({ user, onRemove, onToggle }) {
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
onClick={() => onToggle(user.id)}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
});
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
export default React.memo(UserList);
deps 값 지워서 함수들에서 해당하는 상태값을 참조하지 않게 하기
-> why?
상태가 업데이트 될 때 마다 그 상태값을 참조하는 함수 또한 새로 생성되기 때문에 계속 리렌더링 된다
-> how?
함수형 업데이트를 통해서
setUsers에 등록하는 콜백함수의 파라미터에서 최신 users를 참조할 수 있기 때문에
굳이 참조하라고 deps값을 넣어주지 않아도 되는것임.
함수형 업데이트는 어떤식으로 하는건지??
-> setSomething (value)
으로 상태를 업데이트 해줄 때 함수형으로 해주는 것이다
setSomething(value=>value)
이런 식으로
예를 들면
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users => users.concat(user)); // 함수형 업데이트
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [username, email]); // 참조값에서 users 빼주기
const onRemove = useCallback(id => {
setUsers(users => users.filter(user => user.id !== id)); // 함수형 업데이트
}, []);
const onToggle = useCallback(id => {
setUsers(users => // 함수형 업데이트
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
}, []);