redux helper 라이브러리
redux-devtools
, immerjs
, redux-thunk
, reselect
등의 라이브러리가 미리 포함됨
- configureStore
- createAction
- createReducer
- createSlice
- createSelector
rudex의 createStore 함수를 래핑하며 named parameter로 쉽게 store를 생성
const store = configureStore({
reducer: {
posts: postsReducer,
users: usersReducer
}
})
createStore를 할 때, 여러가지 reducer를 넘길 수 없고 함수 하나를 넘겨야 한다. 이때 state를 분할하여 보내고 싶을 경우 (ex. users, posts, comments...) 각각의 action을 처리하기 위해서는 별도의 reducer1, reducer2, reducer3...이 필요하다. 이러한 번거로운 과정을 하나의 reducer 객체로 받아 combineReducers를 적용하는 것이 configureStore
이다.
Action creator(함수)를 만드는 함수 (= 고차원함수)
const addPost = createAction('post/addPost')
addPost({ title : 'post 1' })
/*
{
type : 'post/addPost',
payload : { title : 'post 1' }
}
*/
생성된 action creator에 데이터를 넘기면, payload 필드로 들어간다.
action creator는 toString()
메서드를 오버라이드*해, 자신이 생성하는 액션의 타입 (=String)을 리턴한다.
* 오버라이드란 ? 부모 클래스가 갖고 있는 메소드를 물려받기는 하지만 그것을 그대로 사용하지 않고 자식 클래스의 필요에 따라 재정의하여 사용하는 것을 말한다. 즉 'post/addPost'가 toString이 되도록 함수가 만들어져 있다는 뜻이 된다.
reducer를 만든다.
const postsReducer = createReducer(initState, builder => {
builder.addCase(addPost, (state, action) => {
state.posts
.push(action.payload)
})
})
createReducer는 상태(ex. initState)를 넘기고 builder
를 인자로 받는 콜백함수를 정의한다. builder의 addCase()
메서드를 이용하여 action(ex. addPost) 마다 특정 reducer를 정의한다. 이렇게 처리를 하면 action 마다 state의 변경을 정의하는데 용이하다. 또한 immerjs
를 내부적으로 사용하여 mutable code를 통해 간편하게 코드를 변경할 수 있다.
여러 redux 구현체(ex. action creator, reducer ...)를 하나의 객체로 모은 것
const postsSlice = createSlice({
name : 'posts',
initialState,
reducers: {
addPost(state, action) {
state.posts
.push(action.payload)
}
}
})
const { addPost } = postsSlice.actions
const reducer = postsSlice.reducer
위와 같이 createSlice는 name, initialState등을 받아 객체로 반환을 하는데, 이 객체의 .actions에는 addPost라는 action creator가 있다. 이와 같이 createSlice 함수를 이용하여 쉽게 action creator와 reducer를 만들 수 있다.
selector 함수를 인자로 받아 state를 이용하여 특정 데이터를 리턴한다.
const postsSelector = state => state.posts
const userSelector = state => state.user
const postsByUserIdSelector = createSelector(
postsSelector,
userSelector,
(posts, user) =>
posts.filter(post =>
post.username === user.username
)
)
postSelector, userSelector 함수를 랩핑하여 특정 username을 지닌 post를 리턴하는 예를 들 수 있다.
또한 내부적으로 데이터를 캐시하고 데이터가 변동이 없다면 캐시된 데이터를 리턴한다. 이는 redux에서 알아서 캐시 관리를 할 수 있다는 뜻이다. 주로 성능향상과 개념적인 정의를 위해 사용한다.