지난번에 배운 redux의 기능을 약간 더 응용해 사용해보자.
우리가 SPA를 만들 때, 다양한 변수들이 다양한 형태로 state에 저장되어 관리를 받을 것이고,
페이지의 기능이 늘어날수록 그 상태의 형태 또한 굉장히 복잡해질 것이다.
예를 들어 간단한 게시판을 만드는데도 다음과 같이 복잡한 initialState가 필요하다.
/* app.js */
const redux = require('redux')
const { createStore } = redux
const initialState = {
user:{
userid:'web7722',
username:'ingoo'
},
comment:{
list:[{ idx:0, content:'asdf', date:'2022-05-03' }]
},
category:{
mainCd:[
{
idx:0,
name:'board',
subCate:[{idx:0, name:'notice'}, {idx:1,name:'freeboard'}]
}
]
},
}
단순히 회원 정보와 댓글, 게시판 카테고리만을 가진 최소한의 어플리케이션도 이 정도로 복잡해진다.
이 경우 가령 1번째 subcategory를 바꾸려면 state.category.mainCd... 순으로 하나하나 경로를 찾아가야 한다.
이런 경우 코드의 관리가 힘들기 때문에 각각의 state를 이루는 요소들을 나누어 따로 관리하고,
이 나누어진 코드들을 마지막에 하나로 합쳐주는 기능이 redux에 존재한다.
저번 글에서 redux를 console.log로 불러왔을 때 있던 함수 중 하나인 combineReducer 함수이다.
이름대로 reducer를 combine 해준다고 생각을 하면 된다.
reducer 뿐만 아니라 각각의 reducer가 관리하는 state 요소들도 분리해 관리하는 것이 가능하다.
우선 initialState들을 다음과 같이 분리한다.
/* app.js */
const initialState_user = {
userid: 'qwerty',
userpw : 1111
}
const initialState_comment = {
list:[{ idx:0, content:'asdf', date:'2022-05-03' }]
}
const initialState_category = {
mainCd:[
{
idx:0,
name:'board',
subCate:[{idx:0, name:'notice'}, {idx:1,name:'freeboard'}]
}
]
}
각 변수들을 잘보면 아까 전처럼 요소들을 중간에서 하나로 묶어주던 user, comment, category가 사라지고,
그 내용들이 바로 초기 state값에 대입되는 것을 알 수 있다.
사라진 객체의 변수명 user, category, comment들은 각 리듀서의 이름으로 대체될 것이다.
각각의 리듀서와 action도 작성해준다.
/* app.js */
(...중략)
// user
const ADD = 'USER/ADD'
const CHANGE_ID = (payload) => ({type:ADD, payload})
const user = (state = initialState_user, action) => {
switch (action.type) {
case ADD :
return {
...state,
userid: action.payload.userid,
userpw: action.payload.userpw
}
default:
return state
}
}
// comment
const CADD = 'COMMENT_ADD'
const COMMENT_ADD = (payload) => ({type:CADD, payload})
const comment = (state = initialState_comment, action) => {
switch (action.type) {
case CADD :
return {
...state,
list: [...state.list, {idx:1, content:action.payload.content, date: '2022-05-03'}]
}
default :
return state
}
}
// category
const TADD = 'CATEGORY/ADD'
const CATE_ADD = (payload) => ({type:TADD, payload})
const category = (state = initialState_category, action) => {
switch (action.type) {
case TADD :
return {
...state,
mainCd:[...state.mainCd, { idx:1, name: action.payload.cate, subCate:[]}]
}
default :
return state
}
}
이제 이렇게 쪼개서 만든 리듀서와 함수들, state들을 하나로 합친다.
/* app.js */
const redux = require('redux')
const { createStore, combineReducers } = redux
// combineReducer 함수를 redux로부터 추가로 가져온다.
(...중략)
const rootReducer = combineReducers({
user,
comment,
category
})
// 각 리듀서들을 combineReducers 함수로 합쳐 rootReducer 변수에 넣는다.
const store = createStore(rootReducer)
// store에 rootReducer 변수를 대입한다.
여기까지 하고 state를 console.log로 불러오면 다음과 같다.
/* app.js */
console.log(store.getState())
/*
{
user: { userid: 'qwerty', userpw: 1111 },
comment: { list: [ [Object] ] },
category: { mainCd: [ [Object] ] }
}
*/
우리가 초기 상태를 설정할 때 따로 변수를 서언해 대입하지 않았음에도 각 객체들이 알아서
각 리듀서의 이름을 key값으로 가지는 것을 알 수 있다.
각각의 state들을 변경해보자.
/* app.js */
(...중략)
store.dispatch(CHANGE_ID({userid: 'sila', userpw: 1357 }))
console.log(store.getState().user)
store.dispatch(CATE_ADD({cate: 'cate2'}))
console.log(store.getState().category)
store.dispatch(COMMENT_ADD({content: 'this is content of new comment'}))
console.log(store.getState().comment)
각 state들이 잘 변경되었다면 이제 이 각각의 코드들을 다른 파일들로 분리해보자.
reducers 폴더를 만들고 그 안에 category.js, comment.js, user.js 파일을 만든 후,
리듀서와 초기 상태, action 생성 함수를 넣고 export 해주면 된다.
/* reducers/user.js */
const initialState = {
userid: 'qwerty',
userpw : 1234
}
const ADD = 'USER/ADD'
const CHANGE_ID = (payload) => ({type:ADD, payload})
const user = (state = initialState, action) => {
switch (action.type) {
case ADD :
return {
...state,
userid: action.payload.userid,
userpw : action.payload.userpw
}
default:
return state
}
}
module.exports = {
user,
CHANGE_ID
}
/* reducers/comment.js */
const initialState = {
list:[{ idx:0, content:'asdf', date:'2022-05-03' }]
}
const CADD = 'COMMENT_ADD'
const COMMENT_ADD = (payload) => ({type:CADD, payload})
const comment = (state = initialState, action) => {
switch (action.type) {
case CADD :
return {
...state,
list: [...state.list, {idx:1, content:action.payload.content, date: '2022-05-03'}]
}
default :
return state
}
}
module.exports = {
comment,
COMMENT_ADD
}
/* reducers/category.js */
const initialState = {
mainCd:[{
idx:0,
name: 'board',
subCate: [{idx:0, name:'notice'}, {idx:1, name:'freeboard'}]
}]
}
const TADD = 'CATEGORY/ADD'
const CATE_ADD = (payload) => ({type:TADD, payload})
const category = (state = initialState, action) => {
switch (action.type) {
case TADD :
return {
...state,
mainCd:[...state.mainCd, { idx:1, name: 'qwert', subCate:[]}]
}
default :
return state
}
}
module.exports = {
category,
CATE_ADD
}
이제 app.js로 돌아와 다음과 같이 코드를 정리할 수 있다.
/* app.js */
const redux = require('redux')
const { createStore, combineReducers } = redux
const { user, USER_ADD } = require('./reducers/user.js')
const { comment, COMMENT_ADD } = require('./reducers/comment.js')
const { category, CATE_ADD } = require('./reducers/category.js')
const rootReducer = combineReducers({
user,
comment,
category
})
const store = createStore(rootReducer)
console.log(store.getState())
store.dispatch(CHANGE_ID({userid: 'sila', userpw: 1357 }))
console.log(store.getState().user)
store.dispatch(CATE_ADD({cate: 'cate2'}))
console.log(store.getState().category)
store.dispatch(COMMENT_ADD({content: 'qwewgfdhzxcv'}))
console.log(store.getState().comment)
'React' 카테고리의 다른 글
error record : styled-compoenents (0) | 2023.03.19 |
---|---|
#17 Router (0) | 2022.05.08 |
#15 Redux part1 (0) | 2022.05.07 |
#14 useMemo, useCallback (0) | 2022.05.02 |
#13 useReducer (0) | 2022.05.01 |