컴포넌트가 동일한 props로 동일한 결과를 렌더링 한다면 React.memo를 호출하여 결과를 저장하여 불필요한 렌더링을 방지할 수 있다.
React.memo는 props 변화에만 영향을 준다. state나 context가 변할 때는 렌더링이된다. 오직 성능 최적화를 위해 사용해야한다.
import React from "react";
const CreateUser = ({ username, age, onCreate, onChange }) => {
console.log("createUser 렌더링");
return (
<>
<input onChange={onChange} value={username} name="username" type="text" />
<input onChange={onChange} value={age} name="age" type="number" />
<button onClick={onCreate}>추가</button>
</>
);
};
export default React.memo(CreateUser);
import React from "react";
const User = React.memo(({ user, onRemove, onToggle }) => {
console.log("User 렌더링");
return (
<>
<div>
<span
style={{
cursor: "pointer",
color: user.active ? "red" : "#000"
}}
onClick={() => {
onToggle(user.id);
}}
>
username: {user.username}, age: {user.age}{" "}
</span>
<button
onClick={() => {
onRemove(user.id);
}}
>
삭제
</button>
</div>
</>
);
});
const UserList = ({ users, onRemove, onToggle }) => {
console.log("UserList 렌더링");
return (
<>
{users.map(user => {
return (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
);
})}
</>
);
};
export default React.memo(UserList);
그렇지만 useCallback의 deps로 넣어 준 users 배열이 계속 바뀌기 때문에 onCreate, onRemove, onToggle이 새로 만들어진다.
따라서 불필요한 렌더링이 발생한다. 여기서 사용할 방법은 함수형 업데이트다. 함수형 업데이트를하면 최신 users를 참조 할 수 있기 때문에
deps가 불필요해진다.
import React, { useState, useRef, useMemo, useCallback } from "react";
import UserList from "./UserList";
import CreateUser from "./CreateUser";
const countActiveUser = users => {
console.log("카운트");
return users.filter(user => user.active).length;
};
export default function App() {
const [inputs, setInputs] = useState({
username: "",
age: ""
});
const { username, age } = inputs;
const [users, setUsers] = useState([
{
id: 1,
username: "Kim",
age: 20
},
{
id: 2,
username: "Lee",
age: "30"
},
{
id: 3,
username: "Choi",
age: "40"
}
]);
const nextId = useRef(4);
const onInputChange = useCallback(e => {
const { value, name } = e.target;
setInputs(inputs => ({
...inputs,
[name]: value
}));
}, []);
const onCreate = useCallback(() => {
const user = {
username,
age,
id: nextId.current,
active: false
};
setUsers(users => [...users, user]);
setInputs({
username: "",
age: ""
});
nextId.current += 1;
}, [username, age]);
const onRemove = useCallback(id => {
setUsers(users =>
users.filter(user => {
return user.id !== id;
})
);
}, []);
const onToggle = useCallback(id => {
setUsers(users =>
users.map(user => {
return user.id === id ? { ...user, active: !user.active } : user;
})
);
}, []);
const count = useMemo(() => countActiveUser(users), [users]);
return (
<div>
<CreateUser
username={username}
age={age}
onChange={onInputChange}
onCreate={onCreate}
/>
<div>activeUser : {count}</div>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
</div>
);
}