[React.js]리액트 react-redux, reselect라이브러리
2021. 7. 30. 21:34ㆍWeb_Programming/React
💻 react-redux
기존에 리액트에서 리덕스 사용
👉 useEffect 훅 & useReducer 훅을 사용하여 상태값을 업데이트
react-redux
👉 useSelector 훅으로 상태값 업데이트 , 자동으로 값 변경시에만 렌더링 가능
App 컴포넌트
Provider에 store를 넘겨 사용 : 액션 처리 시, 이벤트를 받아 하위 컴포넌트가 렌더링 되도록
import React from 'react';
import FriendMain from './friend/container/FriendMain';
import TimelineMain from './timeline/container/TimelineMain';
import { Provider } from 'react-redux';
import store from './common/store';
export default function App() {
return (
<Provider store={store}>
<div>
<FriendMain />
<TimelineMain />
</div>
</Provider>
)
}
import React from 'react';
import { getNextFriend } from '../../common/mockData'; // 데이터베이스 API 샘플코드
import { addFriend } from '../state';
import FriendList from '../component/FriendList';
import { useSelector, useDispatch } from 'react-redux';
export default function FriendMain() {
// 데이터
const friends = useSelector(state => state.friend.friends);
const dispatch = useDispatch();
/* react-redux 사용전
const [, forceUpdate] = useReducer(v => v+1, 0);
// 스토어 함수로 상태변경을 감지하고 강제 업데이트
useEffect(() => {
let prevFriends = store.getState().friend.friends;
const unsubscribe = store.subscribe(() => {
const friends = store.getState().friend.friends;
if (prevFriends !== friends) {
forceUpdate();
}
prevFriends = friends;
});
return () => unsubscribe();
}, []);
*/
// 이벤트
function onAdd() {
const friend = getNextFriend();
dispatch(addFriend(friend));
}
// 렌더링
return (
<div>
<button onClick={onAdd}>친구 추가</button>
<FriendList friends={friends} />
</div>
);
}
💡 useSelector 훅
react-redux에서 상탯값을 가져올 때 사용되는 훅으로 아래와 같이 사용됩니다.
const friends1 = useSelector(state => state.friend.friends);
const friends2 = useSelector(state => state.friend.friends);
const friends3 = useSelector(state => state.friend.friends);
여러 값을 가져올 때, 위처럼 분리해서도 가능하고 하나의 배열 및 객체로 가져오는 것도 가능합니다.
const [friends1, friends2] = useSelector(state => [state.friend.friends1, state.friend.friends2]);
❗ 그냥 위처럼 사용 하면, 배열은 계속 새로 생성되어 계속 렌더링이 되는 문제가 발생
👉 react-redux에서 제공하는 값 비교 함수 shallowEqual을 세 번째 인자로 넣어줍니다.
값 비교 후 변경 시에만 렌더링
import { shallowEqual } from 'react-redux';
const [friends1, friends2] = useSelector(
state => [state.friend.friends1, state.friend.friends2],
shallowEqual
);
+ TIP . 별도의 커스텀 훅으로 관리
import { shallowEqual } from 'react-redux';
function useMySelector(selector) {
return useSelector(selector, shallowEqual);
}
const [v1, v2] = useMySelector(state => [state.v1, state.v2]);
const v3 = useMySelector(state => state.v3); //비효율적(하위 속성 모두 비교) 배열로 반환권장
const [v4] = useMySelector(state => [state.v4]);
💻 reselect 라이브러리
: 메모제이션을 가능하게 해주는 라이브러리
아래와 같이 createSelector를 이용하면,
👉 배열의 값이 변경될 때만, 함수가 수행되도록 해주는 메모제이션기능을 수행
import { createSelector } from 'reselect';
const getFriends = state => state.friend.friends;
export const getAgeLimit = state => state.friend.ageLimit;
export const getShowLimit = state => state.friend.showLimit;
export const getFriendsWithAgeLimit = createSelector(
[getFriends, getAgeLimit],
(friends, ageLimit) => friends.filter(item => item.age <= ageLimit)
)
export const getFriendsWithAgeShowLimit = createSelector(
[getFriendsWithAgeLimit, getShowLimit],
(friendsWithAgeLimit, showLimit) => friendsWithAgeLimit.slice(0, showLimit)
)
사용 코드
const [
ageLimit,
showLimit,
friendsWithAgeLimit,
friendsWithAgeShowLimit,
] = useSelector(state => [
getAgeLimit(state),
getShowLimit(state),
getFriendsWithAgeLimit(state),
getFriendsWithAgeShowLimit(state),
],
, shallowEqual)
/* 사용전
const [
ageLimit,
showLimit,
friendsWithAgeLimit,
friendsWithAgeShowLimit,
] = useSelector(state => {
const { ageLimit, showLimit, friends } = state.friend;
const friendWithAgeLimit = friends.filter(item => item.age <= ageLimit);
return [
ageLimit,
showLimit,
friendsWithAgeLimit,
friendsWithAgeLimit.slice(0, showLimit),
]
}, shallowEqual)
*/
reselcet라이브러리 사용 전
👉 useSelector 훅이 액션이 처리될 때마다 현재 상태의 데이터를 반환
+ friends 값과 ageLimit 값이 변경되지 않았다면 추가적으로 렌더링을 하지는 않지만 filter 연산은 무조건 수행
reselector 라이브러리 사용
👉 friends 와 ageLimit 값이 변경이 되었을 경우에만 filter 연산 수행
+ 셀렉터 코드의 분리를 통해서 코드의 개선 효과
💻 리덕스 사용 팁
리덕스에서,
💡 리듀서에서만 간단하게 관리하는 상태값이라면 별도의 공통함수를 만들면 좀 더 간편하게 사용할 수 있습니다.
// 공통 함수
function createSetValueAction(type) {
return (key, value) => ({ type, key, value });
}
function setValueReducer(state, action) {
state[action.key] = action.value;
}
// 액션, 액션 크리에이터
const SET_VALUE = 'horong/SET_VALUE';
const setValue = createSetValueAction(SET_VALUE);
// 리듀서
function reducer = createReducer(INITIAL_STATE, {
[SET_VALUE]: setValueRecucer,
// ...
});
// 컴포넌트 (상태값을 저장할 이름과 값을 입력)
dispatch(setValue('key', value));
💡 리덕스 코드의 규모가 커지면, 코드를 액션/리듀서의 코드를 분리하는 것이 좋습니다.
💡 또한 코드에서 코드의 이해력과 가독성을 높이기 위해 액션 함수를 객체로 변경하여 묶는 것도 좋습니다.
// 액션, 액션크리에이터
export const types = {
SET_VALUE: 'common/SET_VALUE',
SET_XXX: 'thisComponent/SET_XXX',
}
export const actions = {
setValue: createSetValueAction(SET_VALUE),
setXXX: v => ({ type: 'XXX', data })
}
// 공통 함수
function createSetValueAction(type) {
return (key, value) => ({ type, key, value });
}
function setValueReducer(state, action) {
state[action.key] = action.value;
}
// 리듀서
function reducer = createReducer(INITIAL_STATE, {
[SET_VALUE]: setValueRecucer,
// ...
});
'Web_Programming > React' 카테고리의 다른 글
[React]카카오 REST API 로그인_TS (0) | 2021.09.17 |
---|---|
[React.js]리액트_redux-saga (0) | 2021.08.03 |
[React.js] 리덕스(액션,미들웨어, 리듀서, 스토어) (0) | 2021.07.21 |
[React.js] 리액트의 useEffect 활용법 & 성능 최적화 방법 (0) | 2021.07.19 |
[React.js]리액트 타입선언, 조건부 렌더링, 컴포넌트 재사용성 (0) | 2021.07.16 |