0. 목차
1. 개요
2. combineReducers
1. 개요
어제 포스팅했던 내용에서 이어진다.
// ./reducer/index.js
const initialState = {
number: 0,
};
const rootReducer = (state = initialState, action) => {
const { type } = action;
switch (type) {
case 'increase':
return {
...state,
number: state.number + 1,
};
case 'decrease':
return {
...state,
number: state.number - 1,
};
default:
return state;
}
};
export default rootReducer;
이런식으로 redux 와 reducer를 만들어서 전역에서 관리되는 상태를 만들고 변경하는 걸 했었다.
현재는 initialState 의 프로퍼티가 number하나 뿐이지만
실제로 작업할때는 정말 많은 갯수의 프로퍼티가 들어갈거다.
오늘은 comment 부분을 만들어 보려 하는데
우선은 index.js 에 다 욱여 넣어보고,
combineReducers를 이용해 reducer를 나누고 합치는걸 해보려고 한다.
2. combineReducers
우선 comment 상태를 만들고,
comment 상태를 comment 컴포넌트에 랜더 해보자.
const initialState = {
number: 0,
comment: [
{
userAlias: 'kong',
content: 'ㅎㅇㅎㅇ',
date: '2022-05-01',
},
{
userAlias: 'pea',
content: 'ㅎㅇㅎㅇ2',
date: '2022-05-03',
},
],
};
상태 만들고,
// ./src/pages/comment/index.jsx
import { useSelector, useDispatch } from 'react-redux';
const Comment = () => {
const comment = useSelector((state) =>
state.comment.map((v) => {
return (
<li>
<ul>
<li>작성자: {v.userAliase}</li>
<li>내용: {v.content}</li>
<li>날짜: {v.date}</li>
</ul>
</li>
);
})
);
return (
<>
<h3>Comment Component</h3>
<ul>{comment}</ul>
</>
);
};
export default Comment;
useSelector로 상태를 가져오고 상태에서 comment 만 가져온뒤 map 을 이용해서 jsx 문법으로 화면울 구성하게끔 만들어 주었다.
여기다가 댓글을 작성할 수 있는 input을 만들어주자.
import { useSelector, useDispatch } from 'react-redux';
import { useState } from 'react';
const Comment = () => {
const initialState = {
userAlias: '',
content: '',
};
const [commentState, setCommentState] = useState(initialState);
const changeValue = (e) => {
const {
target: { name, value },
} = e;
setCommentState({
...commentState,
[name]: value,
});
};
const comment = useSelector((state) =>
state.comment.map((v) => {
return (
<li>
<ul>
<li>작성자: {v.userAliase}</li>
<li>내용: {v.content}</li>
<li>날짜: {v.date}</li>
</ul>
</li>
);
})
);
return (
<>
<h3>Comment Component</h3>
<form action="">
<input
type="text"
name="userAlias"
placeholder="작성자"
onChange={changeValue}
/>
<input
type="text"
name="content"
placeholder="내용"
onChange={changeValue}
/>
<button type="submit">등록</button>
</form>
<ul>{comment}</ul>
</>
);
};
export default Comment;
input의 value에따라 변화하는 상태는 굳이 전역에서 관리할 필요가 없으므로,
해당 컴포넌트에 박아두면 된다.
커스텀 훅을 만들어서 따로 관리할 수 있지만,
그게 목적이 아니니까 이번에는 그냥 할거다.
이제 form 이 submit 될때 submit 을 막고,
dispatch를 이용해 전역상태를 변경해주면 된다.
import { useSelector, useDispatch } from 'react-redux';
import { useState } from 'react';
const Comment = () => {
const dispatch = useDispatch();
const initialState = {
userAlias: '',
content: '',
};
const [commentState, setCommentState] = useState(initialState);
const changeValue = (e) => {
const {
target: { name, value },
} = e;
setCommentState({
...commentState,
[name]: value,
});
};
const comment = useSelector((state) =>
state.comment.map((v) => {
return (
<li>
<ul>
<li>작성자: {v.userAliase}</li>
<li>내용: {v.content}</li>
<li>날짜: {v.date}</li>
</ul>
</li>
);
})
);
const submitHandler = (e) => {
e.preventDefault();
if (commentState.userAlias && commentState.content) {
dispatch({ type: 'ADD_COMMENT', payload: commentState });
}
};
return (
<>
<h3>Comment Component</h3>
<form action="" onSubmit={submitHandler}>
<input
type="text"
name="userAlias"
placeholder="작성자"
onChange={changeValue}
/>
<input
type="text"
name="content"
placeholder="내용"
onChange={changeValue}
/>
<button type="submit">등록</button>
</form>
<ul>{comment}</ul>
</>
);
};
export default Comment;
comment 컴포넌트에서는 이렇게 만들어주고
const rootReducer = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case 'increase':
return {
...state,
number: state.number + 1,
};
case 'decrease':
return {
...state,
number: state.number - 1,
};
case 'ADD_COMMENT':
const nowDate = new Date();
const date = `${nowDate.getFullYear()}-${
nowDate.getMonth() + 1
}-${nowDate.getDate()}`;
payload.date = date;
const newComment = [...state.comment, payload];
return {
...state,
comment: newComment,
};
default:
return state;
}
};
루트 리듀서도 수정을 해주었다.
그런데 지금 댓글 추가 기능만 만들엇는데도 이이이만큼 길어지는데,
삭제 업데이트 까지 만들면 더 길어질거다.
그래서 reducer를 다 쪼개고,
combineReducers로 합쳐주면 코드가 읽기도 편하고
관리하기도 편하고, 재사용성도 높아진다.
그렇다고 한다..
그럼 쪼개 보자.
// ./src/reducer/counter/counter.js
const initalState = {
number: 0,
};
const counter = (state = initalState, action) => {
const { type, payload } = action;
switch (type) {
case 'increase':
return {
...state,
number: state.number + 1,
};
case 'decrease':
return {
...state,
number: state.number - 1,
};
default:
return state;
}
};
export default counter;
카운터를 담당하는 reducer 를 만들고
// ./src/reducer/comment/commentReducer.js
const initialState = {
commentList: [
{
userAlias: 'kong',
content: 'ㅎㅇㅎㅇ',
date: '2022-05-01',
},
{
userAlias: 'pea',
content: 'ㅎㅇㅎㅇ2',
date: '2022-05-03',
},
],
};
const comment = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case 'ADD_COMMENT':
const nowDate = new Date();
const date = `${nowDate.getFullYear()}-${
nowDate.getMonth() + 1
}-${nowDate.getDate()}`;
payload.date = date;
const newComment = [...state.comment, payload];
return {
...state,
comment: newComment,
};
default:
return state;
}
};
export default comment;
comment 를 담당하는 리듀서를 만들었다.
// ./src/reducer/index.js
import { combineReducers } from 'redux';
import comment from './comment/commentReducer';
import counter from './counter/counter';
const rootReducer = combineReducers({
comment,
counter,
});
export default rootReducer;
rootReducer 에서 combineReducers 를 이용해서
각각의 reducer를 합쳐준다.
이렇게 하면 전역에서 관리하는 상태는
state = {
comment: [
// ...
],
counter : {
// ...
}
}
이런 형태가 된다.
각각 컴포넌트에서 변경된 상태에 따라 조금씩 코드를 수정해주면 정상적으로 동작하는걸 확인 할수 있다.
const initialState = {
commentList: [
{
userAlias: 'kong',
content: 'ㅎㅇㅎㅇ',
date: '2022-05-01',
},
{
userAlias: 'pea',
content: 'ㅎㅇㅎㅇ2',
date: '2022-05-03',
},
],
};
const comment = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case 'ADD_COMMENT':
const nowDate = new Date();
const date = `${nowDate.getFullYear()}-${
nowDate.getMonth() + 1
}-${nowDate.getDate()}`;
payload.date = date;
const newCommnetList = [...state.commentList, payload];
return {
...state,
commentList: newCommnetList,
};
default:
return state;
}
};
export default comment;
너무 편안하다.
전체코드는 Github
댓글