- react-redux의 shallowEqual 사용하기 목차
| react-redux
Provider
react-redux 는 root-container
에서 Provider
를 사용하여 store
값을 할당해주면 됩니다.Provider
components 에서는 리액트에서 action
이 처리 됐을 때, 이벤트를 받아서 하위에 있는 다른 컴포넌트가
다시 렌더링 될 수 있도록 도와주는 역할을 합니다.
활용 예시
import { Provider } from 'react-redux';
//store를 가져옵니다
//여기서 첫 번째 인자인 reducer는 combineReducers()등을 구현한 1개 이상의 리듀서들을 뜻합니다.
store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION___?.());
export default App (){
<Provier store = {store}
<div>
<...>
</div>
</Provider>
}
기존 FriendMain.js code
import { useEffect, useReducer } from "react";
import { getNextFriend } from "../../common/mockData";
import store from "../../common/store";
import FriendList from "../component/FriendList";
import { addFriend } from "../state";
//FriendMain
function FriendMain() {
const [, forceUpdate] = useReducer(v => v + 1, 0);
//딱 한 번만 로딩 되도록
useEffect(() => {
//전에 데이터 friends
let prevFriends = store.getState().friend.friend;
//unsubscribe 함수는 dispatch 함수를 실행 시키는 함수
//store값이 변하는지 계속 관찰함.
const unsubscribe = store.subscribe(() => {
//현재 friends
const friends = store.getState().friend.friend;
//전 friends와 현재 friends가 같지 않다면
//즉 변화가 발생하면 렌더링
if (prevFriends !== friends) {
//렌더링 실행
forceUpdate();
}
//그 후 prevFriends 값을 현재 friends 배열로 update
prevFriends = friends;
});
return unsubscribe;
}, []);
function onAdd() {
const friends = getNextFriend();
store.dispatch(addFriend(friends));
}
const friendList = store.getState().friend.friend;
return (
<div>
<button onClick={onAdd} >친구 리스트 추가</button>
<FriendList friends={friendList} />
</div>
)
};
export default FriendMain;
해당 코드에서는 이전 data
값과 비교를 위한 변수가 필요했었습니다.
( 이유 : 불필요한 렌더링을 막기 위하여 비교를 했었음 )
useSelector Hook 사용
useSelector
란
위의 코드에서 react-redux
를 사용한다면 다음과 같은 코드로 update 됩니다.
바로 ! useSelector()
와 useDispatch()
Hook을 사용하면 됩니다.
업데이트 된 FriendMain.js code
//useSelector를 사용하여 현재 상태값에서 가져올 data를 선택합니다.
const friends = useSelector(state => state.friends.friends);
위와 같이 만들어주면 store.getState()
를 사용하여 현재 데이터를 가져올 필요가 없이useSelector()
만으로 가져올 수 있습니다.
여러개의 state 값을 가져오고 싶다면 ?
1.useSelector
를 여러번 사용하기
const e1 = useSelector(state => ... )
const e2 = useSelector(state => ... )
const e3 = useSelector(state => ... )
위와 같은 방식으로 선언하여 사용해주면 됩니다.
하지만 너무 보기 안 좋죠?
2.조금 개선된 방법인 배열, 객체 형태로 받기
export default function FriendMain(){
//배열로 여러개의 state 값 받기
const [friends,friends2] = useSelector(state => [state.friend.friends, state.friend.friends2]);
//객체로 여러개의 state 값 받기
const {friends, name } = useSelector(state => {state.friend.friends, state.friend.friends2.name });
...
}
하지만 이 방법에도 문제가 조금 존재합니다.
배열이 매번 생성이 되기 때문에 안에 있는 값들이 변경되지 않더라도, redux에서 action이 처리될 때 마다 불필요하게 FriendMain 컴포넌트가 랜더링될 수 있다는 단점이 존재합니다.
그럼 어떻게 해야할까?
바로 shallowEqual
함수를 두 번째
인자로 넣어줍니다.
// 두 번째 인사로 shallowEqual 넣기
const[friends, friends2] = useSelector(state => [state,friend.friends, state.friend.friends2], shallowEqual);
shallowEqual
함수는 얕은 비교
를 하기 때문에 배열을 입력했을 때 배열의 레퍼런스만 비교하는 것이 아니라 안에있는 friends와 friends2를 각각 비교
하기 때문에 해당 값이 변경되었을 때만 컴포넌트가 렌더링될 것 입니다.
하지만 매번 입력하기도 귀찮기 때문에
커스텀 Hook 을 만들어 사용하면 편리합니다.
shallowEuqal을 위한 custom Hook
커스텀 hook
function useMySelector(selector){
//useSelector 훅과 shallowEqual을 사용한 것을 return해줍니다.
return useSelector(selector,shallowEqual);
}
function MyCompoenent(){
//위에서 선언한 useMySelector 훅으로 첫 번째 인자로 (state=> ... ) 들을 전달해주면
//반환값으로는 shallowEqual을 사용하여 비교한 값으로 return해줍니다.
const[value1, value2] = useMySelector(state => [state.value1,state.value2];
const value3 = useMySelector(state=> state.value3);
const [value4] = useMySelector(state => [state.value4]);
}
여기서 주의할 점은 배열을 입력하지 않고 사용을 했을 때, (2번째 value3 의 경우)
useMySelector(state => state.value3);
배열을 입력하지 않고 위와 같이 코드를 사용 할 때에는, value3의 모든 속성값을 비교하기 때문에 성능상 비효율적일 수 있습니다.
따라서 값을 하나만 반환 하더라도 "[]" 배열로 감싸서 반환해야합니다.
'React' 카테고리의 다른 글
제너레이터(Generator) (0) | 2021.02.23 |
---|---|
리덕스 reselect 사용하기 (0) | 2021.02.22 |
redux-saga (0) | 2021.02.21 |
CORS와 Webpack DevSercer Proxy (0) | 2021.02.18 |
redux-thunk란? (0) | 2021.02.18 |