store 생성 로직
, reducers 로직
, 비동기 네트워크 통신 로직
이 하나의 Store 폴더에 모아져 있었습니다. 안 그래도 리덕스의 단점 중 하나인 코드 길이가 길어져 가독성이 떨어진 경험이 있어 그것을 염두 해 store, reducers, sagas 폴더 3개로 구분했습니다.
store 관련 폴더입니다.
reduxToolkit의 configureStore를 이용해 store 생성, middleware 설정, devTools 관리를 한 번에 구현할 수 있습니다.
const store = configureStore({
reducer: rootReducer,
middleware: [sagaMiddleware],
devTools: process.env.NODE_ENV !== 'production'
})
reducers 관련 폴더입니다.
index.js에서 combineReducers을 이용해 분리한 reducer를 모았습니다. books 하나 뿐이지만 확장성을 위해 작성했습니다.
const rootReducer = combineReducers({
books
})
기본적으로 redux toolkit
의 createSlice
를 이용해 굉장히 깔끔하고 짧게 redcuers를 구현됐다고 생각됩니다. 다만 initialState를 밖으로 꺼내는 걸 선호하기 때문에 밖으로 꺼내고 Status 관련된 변수들을 상수화 시켜 관리했습니다.
getItemsFailure 액션일 때 상태가 빠져있어 추가했습니다.
setBooks라는 함수는 state를 얻을 수 있는 함수입니다. 하지만 useSelector hook
을 이용해 바로 state를 가져올 수 있기 때문에 삭제했습니다.
fetchBooks 함수를 이용해 비동기적으로 네트워크 통신을 할 수 있도록 잘 구현됐다고 생각합니다. 하지만 확장성을 위해 비동기 네트워크 통신 폴더에 분리할 필요성이 있어 분리했습니다. ( Saga 폴더에서 다시 )
// utils/constants
export const STATUS = {
Idle: 'idle',
Loading: 'loading',
Success: 'success',
Failure: 'failure'
}
// reducers/books
const initialState = {
items: [],
totalItems: 0,
startIndex: 0,
status: STATUS.Idle,
error: null
}
const booksSlice = createSlice({
name: 'books',
initialState,
reducers: {
getItemsFailure(state, action) {
state.status = STATUS.Failure
state.error = action.payload
}
}
})
( 삭제 ) export const selectBooks = state => state.books
리덕스의 비동기 네트워크 처리를 위해 redux-saga
를 이용했습니다. 사실 작성된 코드는 redux-thunk
에 가까웠지만 다양한 effect와 확장성을 염두 해 redux-saga를 선택했습니다.
index.js에서 아직 하나의 saga지만 확장성을 염두 해 한 번에 처리했습니다.
export function* rootSaga() {
yield all([booksSaga()])
}