React.memo는 컴포넌트의 성능 최적화(쓸데없는 리렌더링 방지)를 위해서 사용한다.
사용법은 간단하다.
전에 만들었던 UserList
와 CreateUser
의 마지막 줄에다가 React.memo로 export 하는 컴퍼넌트를 씌워주면 된다.
export default React.memo(UserList)
export default React.memo(CreateUser)
UserList
에서 따로 만든 User
컴포넌트 또한 React.memo로 둘러싸준다.
const User = React.memo(function User({user, onRemove, onToggle}){
const {username, email,id, active} = user;
useEffect(() => {
console.log('user 값이 설정됨')
console.log(user);
return () => {
console.log('user 값이 바뀌기 전');
console.log(user);
}
}, [user]);
return(
<div>
<b style={{
color: active? 'green' : 'black',
cursor: 'pointer'
}}
onClick={() => onToggle(id)}
>{username}</b>
<span>({email})</span>
<button onClick={() => onRemove(id)}>삭제</button>
</div>
);
});
여기까지 진행하면 사용자가 input창에 입력하는 동안에 다른 컴퍼넌트가 리렌더링 되지 않는 모습을 볼수 있다.
하지만, user의 활성화/비활성화 변경에 따른 리렌더링의 최적화는 아직 이루어지지 않은 상태이다(하나를 클릭해서 글씨색깔을 바꿔도 나머지 컴퍼넌트들이 렌더링 되는 상황을 의미한다).
먼저 이 현상이 왜 일어나는지 부터 알아야한다.
UserList
에는 onRemove
와 onToggle
을 전달해주고 있다.
나는 UserList
에 React.memo
를 설정해서 props
가 바뀌지 않으면 다시 렌더링 되지 않게끔 작성했다.
그런데, App.js
에서의 onRemove
onToggle
의 렌더링 조건값에 [users]가 존재한다. 따라서 배열 users
가 변하면 onRemove
onToggle
도 렌더링 되고, UserList
입장에서는 두 함수(props에 속한다)가 렌더링 되었으므로 UserList
전체가 렌더링 되며 배열의 값 출력방식을 작성한 컴퍼넌트 User
또한 리렌더링이 되는 것이다.
그럼 이 현상이 일어나지 않게 하려면 어떻게 하면 될까?
useState의 함수형 업데이트를 해주면 된다.
현재 onCreate
는 아래와 같이 작성 되어있다.
const onCreate = useCallback(() => {
const user ={
id: nextId.current,
username,
email
};
setUsers([...users, user]);
setInputs({
username: '',
email: ''
});
console.log(nextId.current);
nextId.current +=1;
},[username,email,users]);
이때 콜백함수의 두번째 파라미다의 요소중 users를 제거하려면
setUsers(users => [...users, user]);
라고 쓰면 아래의 파라미터에 users를 쓸 필요가 없어진다.
위 구문의 뜻은 setUsers에 등록하는 콜백함수의 파라미터에서 최신 users를 조회한다는 뜻이다.
다른 함수도 같은 방식으로 처리한다.
근데 확인은 어떻게 함?
컴퍼넌트 내부 최상위에 console.log('컴퍼넌트 이름')
이라고 작성한뒤 리액트 앱을 실행해서 확인을해보면 된다. 만약 관련 없는 일임에도 불구하고 콘솔로그에 컴퍼넌트 이름이 나온다면 렌더링 최적화가 실패한 것이고, 해당 컴퍼넌트의 작업만 실행할때 문구가 출력된다면, 최적화가 잘 된것이다.