redux의 action 정의 및 reducer 정의를 위한 파일 관리를 위해 modeuls 폴더를 생성하였다.
기존의 검색창에서 사용하던 state 관리를 하기 위해 다음과 같이 정의하였다.
import { createAction, handleActions } from 'redux-actions';
// action 정의
const SET_LOCATION = 'searchForm/SET_LOCATION';
const SET_CHECKIN = 'searchForm/SET_CHECKIN';
const SET_CHECKOUT = 'searchForm/SET_CHECKOUT';
const SET_GUESTNUM = 'searchForm/SET_GUESTNUM';
// action object 생성
export const setLocation = createAction(SET_LOCATION, location => location);
/* same to {
type: searchForm/SET_LOCATION
payload: location
}
*/
export const setCheckin = createAction(SET_CHECKIN, checkin => checkin);
export const setCheckout = createAction(SET_CHECKOUT, checkout => checkout);
export const setGuestNum = createAction(SET_GUESTNUM);
// initial state
const initialState = {
location: '',
checkin: '',
checkout: '',
guestNum: {
adult: 0,
child: 0,
infant: 0,
},
};
// reducer 정의
const searchForm = handleActions(
{
[SET_LOCATION]: (state, { payload: location }) => {
return {
...state,
location,
};
},
[SET_CHECKIN]: (state, { payload: checkin }) => {
return {
...state,
checkin,
};
},
[SET_CHECKOUT]: (state, { payload: checkout }) => {
return {
...state,
checkout,
};
},
[SET_GUESTNUM]: (state, { payload: guestNum }) => {
return {
...state,
guestNum,
};
},
},
initialState,
);
export default searchForm;
redux store
에는 하나의 reducer만 연결 할 수 있기 때문에 combineReducers 함수
를 이용하여 통합해야 한다.
import { combineReducers } from 'redux';
import searchForm from './searchForm';
const rootReducer = combineReducers({
searchForm,
});
export default rootReducer;
현재는 searchForm이라는 reducer 하나만을 가지고 있지만 또 다른 reducer가 존재 시 추가적으로 붙여주면 된다.
// ex) const rootReducer = combineReducers({ searchForm, addedReducer });
react의 최상위 파일인 index.js에서 redux store을 연결해야 렌더링하는 어떤 컴포넌트에서든지 redux store에 접근할 수 있기 때문
에 index.js파일에서 진행해야 한다.
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import App from './App';
import rootReducer from './modules';
// rootReducer가 연결된 redux store 생성
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
redux-devtools-extension를 연동하고 싶다면 아래와 같이 작성하면 된다.
import { composeWithDevTools } from "redux-devtools-extension"; const store = createStore(rootReducer, composeWithDevTools());
redux의 state와 action에 접근할 때는 hook을 사용하면 쉽게 접근 할 수 있다.
import { useDispatch, useSelector } from 'react-redux';
// redux action 접근
const dispatch = useDispatch();
// redux state 접근
const { location, checkin, checkout, guestNum } = useSelector(state => state.searchForm);
function changeLocation(region) {
// setLocation은 2)번에서 생성한 action 객체
dispatch(setLocation(region));
}
(예전에 사용했을 때는 mapStateToProps, mapDispatchToProps인 HOC 방식으로 사용했던 것 같은데 hook으로 대체하니까 훨씬 간편하다.)
기존의 useState hook을 이용하던 결과와 동일한 결과를 얻을 수 있었지만 redux를 적용함으로써 불필요한 state 전달도 줄어들었고 그에 따라 state관리도 편해졌다.
나중에 프로젝트 규모가 커진다면 redux는 필수로 사용해야한다고 생각들만큼 유용한 라이브러리인것 같다.
현재는 검색관련 시, 인원을 증가하고 감소시키는데 필요한 로직들을(성인 없이 어린이, 유아를 증가시킬 경우, 0일 경우, 어린이, 유아 값이 1이상인데 성인을 0으로 만드는 경우 등등..) container 컴포넌트에 구현을 하였고 dispatch를 통해 값을 저장하는 용도로만 redux를 사용했다.
위의 방식이 옳은 방식인지 아니면 이러한 로직들을 redux 안에서 구현해야 하는지 모르겠다..