
내 기준 그나마 깔끔하게(?) 쓰는방법을 공유해보고자 한다.
바로 LEGO
왜 이렇게 많이 설치해야 하냐면... 다 필요하기 때문..!!
거두절미하고 설치 ㄱㄱ
$ npm i redux react-redux @reduxjs/toolkit

DevTools를 설치하면 chrome의 개발자도구에 Redux탭이 생기면서 state값들이 바뀔때마다 그 정보를 쉽게 볼 수 있어서 아주 편리하다. 🥹
import {configureStore} from '@reduxjs/toolkit';
const store = configureStore({
reducer: {
}
});
export default store;
store는 모든 리듀서들을 합쳐주는 역할을 함.
import {Provider} from 'react-redux';
import store from './_store/store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
);
최상위 컴포넌트에다가 연결
CRUD로 대표적인게 댓글기능이니.. reply.slice.js파일로 하겠다.
import {createSlice} from '@reduxjs/toolkit';
const replySlice = createSlice({
name: 'reply',
initialState: {
replyList: []
},
reducers: {
addReply: (state, action) => {
return {
...state,
replyList: [...state.replyList, action.payload]
};
}
}
});
export const {addReply} = replySlice.actions;
export default replySlice.reducer;
import {configureStore} from '@reduxjs/toolkit';
import replyReducer from './reply.slice';
const store = configureStore({
reducer: {
reply: replyReducer
}
});
export default store;
스토어에 등록!!
import React, {useState} from 'react';
import {useDispatch, useSelector} from 'react-redux';
import { addReply } from '../_store/reply.slice';
function TestPage() {
const [commentValue, setCommentValue] = useState('');
const [commentList, setCommentList] = useState('');
const handleWriteComment = (e) => {
console.log(e.target.value);
};
return (
<div>
<input
placeholder="댓글 작성..."
value={commentValue}
onChange={handleWriteComment}/>
<button>댓글달기</button>
<ul>
</ul>
</div>
)
}
export default TestPage;
state값을 바꿀땐 useDispatch를 사용하고, 값을 읽어올때는 useSelector를 사용한다.

날것의 UI는 귀엽다
import React, {useState} from 'react';
import { setReplyList, addReply } from '../_store/reply.slice';
import {useDispatch, useSelector} from 'react-redux';
import './TestPage.scss';
function TestPage() {
const dispatch = useDispatch();
const rdxReply = useSelector((state) => state.reply);
const [commentValue, setCommentValue] = useState('');
const handleWriteComment = (e) => {
setCommentValue(e.target.value);
};
const onclicksubmit = () => {
if(commentValue === '') {
console.log('no comment value');
return;
}
dispatch(addReply(commentValue));
setCommentValue('');
};
return (
<div className='testPage-wrapper'>
<div className=''>
<input placeholder="댓글 작성..." value={commentValue} onChange={handleWriteComment}/>
<button onClick={onclicksubmit}>댓글달기</button>
</div>
<ul>
{rdxReply.replyList.map((listItem, idx) => {
return (
<li key={idx}>{listItem}</li>
);
})}
</ul>
</div>
)
}
export default TestPage;\
dispatch(addReply(commentValue));
dispatch를 사용해서 addReply 액션을 수행한다.
const rdxReply = useSelector((state) => state.reply);
이렇게 사용하면 추후에 reply 내부 state값을 새로 추가할때도 rdxReply.xxx 이런식으로 값을 가져올 수 있음.

아주 저장이 잘됨.
이제 create, read를 수행하였으니 수정하고 삭제도 해보자.
import {createSlice} from '@reduxjs/toolkit';
const replySlice = createSlice({
name: 'reply',
initialState: {
replyList: []
},
reducers: {
setReplyList: (state, action) => {
return {
...state,
replyList: action.payload
};
},
addReply: (state, action) => {
return {
...state,
replyList: [...state.replyList, action.payload]
};
},
setIsEdit: (state, action) => {
const updatedIdx = action.payload.idx;
state.replyList[updatedIdx].isEdit = action.payload.isEdit;
},
updateReply: (state, action) => {
const updatedIdx = action.payload.idx;
state.replyList[updatedIdx].comment = action.payload.comment;
state.replyList[updatedIdx].isEdit = action.payload.isEdit;
}
}
});
export const {setReplyList, addReply, setIsEdit, updateReply} = replySlice.actions;
export default replySlice.reducer;
setReplyList, setIsEdit, updateReply 3개의 액션들을 추가한다.
import React, {useState} from 'react';
import { setReplyList, addReply, setIsEdit, updateReply } from '../_store/reply.slice';
import {useDispatch, useSelector} from 'react-redux';
import './TestPage.scss';
function TestPage() {
const dispatch = useDispatch();
const rdxReply = useSelector((state) => state.reply);
const [commentValue, setCommentValue] = useState('');
const [editValue, setEditValue] = useState('');
// 댓글 onchange
const handleWriteComment = (e) => {
setCommentValue(e.target.value);
};
// 댓글 수정 onchange
const handleEditInput = (e) => {
setEditValue(e.target.value);
};
// 댓글 달기
const onclicksubmit = () => {
if(commentValue === '') {
console.log('no comment value');
return;
}
dispatch(addReply({comment: commentValue, isEdit: false}));
setCommentValue('');
};
// 댓글 수정
const modifyClick = (idx) => {
dispatch(setIsEdit({idx: idx, isEdit: true}));
};
// 댓글 삭제
const deleteClick = (deleteIdx) => {
const newCommentList = rdxReply.replyList.filter((listItem, idx) => idx !== deleteIdx);
dispatch(setReplyList(newCommentList));
};
// 수정 ok
const editOK = (idx) => {
if(editValue === '') {
console.log('editValue empty..');
return;
}
dispatch(updateReply({comment: editValue, idx: idx, idEdit: false}));
setEditValue('');
};
// 수정 취소
const editCancel = (idx) => {
setEditValue('');
dispatch(setIsEdit({idx: idx, isEdit: false}));
};
return (
<div className='testPage-wrapper'>
<div className='write-wrapper'>
<input placeholder="댓글 작성..." value={commentValue} onChange={handleWriteComment}/>
<button onClick={onclicksubmit}>댓글달기</button>
</div>
<ul className='ul-wrapper'>
{rdxReply.replyList.map((listItem, idx) => {
return (
<li key={idx}>
<div>
{listItem.isEdit ? (<input placeholder="댓글 작성..." onChange={handleEditInput} value={editValue}></input>) : (<span>{listItem.comment}</span>)}
</div>
<div className='list-item'>
{ listItem.isEdit ? (
<>
<button onClick={() => editOK(idx)}>확인</button>
<button onClick={() => editCancel(idx)}>취소</button>
</>
) : (
<>
<button onClick={() => modifyClick(idx)}>수정</button>
<button onClick={() => deleteClick(idx)}>삭제</button>
</>) }
</div>
</li>
);
})}
</ul>
</div>
)
}
export default TestPage;
댓글 수정 누르면 수정 관련 UI가 보여야하고 수정 ok나 수정 취소를 누르면 다시 원복이 되어야한다.

끄읏👏