Redux의 useSelector 렌더링 문제 해결
문제점
Redux의 useSelector
로 특정 데이터를 구독하는 컴포넌트는, 리덕스 스토어에서 특정 데이터(구독하지 않은 것일 수도 있음)가 변경되는 경우 알림을 받는다.
새로운 상태와 현 상태를 비교해 값이 다르면 리렌더링한다.
보통 useSelector(state => ({a: state.a, b: state.b}))
이 selector에 전달한 콜백의 리턴 값을 기준으로 비교한다.
위의 예시는 매번 새로운 객체가 생성되기 때문에 값이 다른 것으로 판단하고 리렌더링한다. (구독하는 데이터가 변경되지 않았음에도 불필요한 리렌더링)
해결
Object를 새로 만들지 않도록 State 쪼개기
// 변경 전 const { modalVisible, bgColor, src, alt } = useSelector(state => ({ modalVisible: state.imageModal.modalVisible, bgColor: state.imageModal.bgColor, src: state.imageModal.src, alt: state.imageModal.alt, })); // 변경 후 const modalVisible = useSelector(state => staet.imageModal.modalVisible) // ..생략
새로운 Equality Function 사용
useSelector
의 2번째 인자로 Equality Function(상태 비교 함수 - 렌더링 여부 판단)을 전달할 수 있다.redux의
shallowEqual
이나 직접 커스텀해서 전달해서 쓰도록 한다.const { modalVisible, bgColor, src, alt } = useSelector(state => ({ modalVisible: state.imageModal.modalVisible, bgColor: state.imageModal.bgColor, src: state.imageModal.src, alt: state.imageModal.alt, }), shallowEqual);
Redux Reselect를 통한 렌더링 최적화
Redux Reselect: Redux에 저장된 여러 개의 데이터를 불러와서 가공해서 사용할 수 있게 해준다.
const selectFilteredPhotos = createSelector(
[(state) => state.photos, (state) => state.category],
(photos, category) => (photo.filter(photo => photo.category === category))
)
데이터 필터링 등을 처리할 때 유용하게 쓸 수 있다.
컴포넌트 안에서 필터링 하는 것에 비해 오버헤드(데이터 필터링)를 줄이고, 불필요한 리렌더링을 줄일 수 있다.
동작이 recoil의 selector
와 매우 비슷하다.
reselect
는 memoization
을 사용해서, 인자가 같다면 값을 계산하지 않고 메모이즈된 값을 사용한다.
그렇기 때문에 createSelector
의 2번째 인자는 순수함수가 들어가야 한다.
'프론트엔드 > 성능 최적화' 카테고리의 다른 글
렌더링 성능 최적화 - Layout Shift 피하기 (0) | 2023.05.01 |
---|---|
렌더링 성능 최적화 - 애니메이션 (0) | 2023.05.01 |
렌더링 성능 최적화 - Bottleneck code (0) | 2023.05.01 |
로딩 성능 최적화 - 텍스트 압축, 불필요한 CSS 제거 (0) | 2023.04.28 |
로딩 성능 최적화 - 캐시 (0) | 2023.04.28 |