useShallow
정의
- selector의 반환 값을 얕은 비교로 판단하여 불필요한 리렌더링을 방지하는 훅
- Zustand에서 제공하는 훅
- 객체의 속성 값들이 변경되었을 때만 컴포넌트를 리렌더링한다.
Object.is
와 유사하게 동작한다.
특징
- 얕은 비교
- 객체의 참조가 아닌, 내부 속성 값들을 얕게 비교하여 변경 여부를 판단한다.
- 랜더링 최적화
useStore(selector)
를 사용할 때, selector가 반환하는 객체가 동일한 참조를 유지하더라도
내부 값이 변경되면 리렌더링을 유발할 수 있다.useShallow
를 사용하면 위의 경우에 발생하는 리랜더링을 방지할 수 있다.
- 선택적 구독
- 컴포넌트가 필요한 상태만 선택적으로 구독할 수 있다.
장점
- 불필요한 리렌더링을 줄여 애플리케이션의 성능을 향상시킬 수 있다.
- 동일한 객체 상태의 일부를 구독하는 컴포넌트의 수가 많을수록 효과적이다.
- 객체나 배열 등에서 최상위 값만 변경될 때 리랜더링된다.
- selector 패턴과 결합하기 쉽다.
단점
- 깊은 비교가 필요할 때는 사용할 수 없다.
- 내부 객체나 배열의 변경은 감지하지 못 한다.
- 남용하면 오히려 문제가 커질 수 있다.
- 가독성을 해칠 수도 있다.
- 리랜더링이 필요한데 리랜더링이 안 될 수도 있다.
기본 사용법
import하기
useState 사용하듯이 import 받아서 사용하면 된다.
import { useShallow } from 'zustand/react/shallow';
저장소 코드
import { create } from "zustand";
const useUserStore = create(
(set, get) => ({
userInfo: {
name: '',
email: '',
},
updateName: (newName) =>
set({
userInfo: { ...get().userInfo, name: newName },
}),
updateEmail: (newEmail) =>
set({
userInfo: { ...get().userInfo, email: newEmail },
}),
}
));
export default useUserStore;
실제 사용법
import useUserStore from "../../store/03_useShallow/useUserStore";
import { useShallow } from 'zustand/shallow';
function Component() {
// userInfo 객체의 name, email 중 하나라도 변경되면 리렌더링
const { name, email, updateName, updateEmail } = useUserStore(
useShallow(
(state) => ({
name: state.userInfo.name,
email: state.userInfo.email,
updateName: state.updateName,
updateEmail: state.updateEmail,
}),
)
);
console.log("랜더링 실행");
return (
<div>
<h2>회원 정보</h2>
<p>Name: {name}</p>
<p>Email: {email}</p>
<button onClick={() => updateName('누군가의 이름')}>이름 수정</button>
<button onClick={() => updateEmail('누군가의 이메일')}>이메일 수정</button>
</div>
);
}
export default Component;