Nay mình sẽ làm một example React cùng với Redux-Toolkit cho mọi người xem thử nhé, nói chung nó cũng đơn giản thôi. Mình làm ví dụ về comment, bao gồm các chức năng như( Add, Update, Remove), Okay let's go @@
Github: Redux-Toolkit CRUD example with React Hooks
# Install Project Redux-Toolkit
npx create-react-app my-app --template redux
Nhiệm vụ như sau:
Create commentSlice.js
Create Component Comment.js
Create comment.module.css
Add commentReduce to Store.js
Bạn sẽ thấy thư mục project của mình như sau:
Tiến hành khởi tạo commentSlice.js
Create commentSlice.js trong đường dẫn thư mục /features/comment, trong file này ta cần cấu hình một số state, actions trong reducers để ta có thể gọi chúng trong Comment.js
import { createAsyncThunk, createSlice, current } from '@reduxjs/toolkit';
//setup state
const initialState = {
comments: [],
};
export const commentSlice = createSlice({
name: 'comment',
initialState,
reducers: {
add: (state,action) => {
// setup opject comment
let cmt = {
_id:1,
_cmt:action.payload.cmt
}
// kiểm tra đã có comment nào chưa, nếu có ta setup id bằng chiều dài của mảng + 1
if(state.comments.length>0) cmt._id = state.comments.length + 1
// thêm comment vào mảng
state.comments.push(cmt)
},
update: (state, action) => {
//lấy dữ liệu từ state ra
let data = state.comments;
/**
* ta có thể sử dụng current để console dữ liệu ra xem trước
*/
console.log(current(data))
//kiểm tra có _id comment trùng với action.payload._id không, nếu có tiến hành update tại vị trí đó
data.map(item=>{
if(item._id===action.payload._id) item._cmt = action.payload._cmt
})
// cập nhật lại state.comments kết quả mới
state.comments = data
},
remove: (state,action) =>{
//kiểm tra xóa _id trong mảng comments, sau đó cập nhật mảng comments lại
state.comments = state.comments.filter(item=>item._id!=action.payload._id)
}
},
});
/*
kết xuất các function add, update, remove
trong Comment.js ta có thể gọi nó, để ta có thể dispatch action
import { add , update , remove , selectComments } from './commentSlice';
let payload = {
cmt : body
}
dispatch(add(payload))
*/
export const { add, update, remove } = commentSlice.actions;
/*
lấy giá trị data comments
trong Comment.js ta có thể select nó ra : const data = useSelector(selectComments)
*/
export const selectComments = (state)=> state.comment.comments;
export default commentSlice.reducer;
Mình cũng đã giải thích một số chức năng trong đoạn code trên.
Create Component Comment.js
Ta tiến hành tạo Comment.js để cài đặt giao diện cho người dùng đăng comment thôi
import React, { useEffect, useState } from 'react'
import styles from './comment.module.css';
import { add , update , remove , selectComments } from './commentSlice';
import { useDispatch, useSelector } from 'react-redux';
export default function Comment() {
const dispatch = useDispatch();
const [body,setBody] = useState();
//select state.comments từ trong commentSlice.js
const data = useSelector(selectComments)
//**set state comment edit */
const [dataEdit,setDataEdit] = useState()
//check onClick edit
const [edit,setEdit] = useState(false);
/** add comment **/
const addComment = ()=>{
let payload = {
cmt : body
}
dispatch(add(payload))
}
/** show modal edit comment **/
const editComment=(item)=>{
//set data edit, để hiển dữ liệu ra modal cần chỉnh sửa
setDataEdit(item);
//set onClick edit = true, để hiển thị modal cần chỉnh sửa
setEdit(true);
}
/**update comment */
const updateComment =()=>{
//btn update nó
dispatch(update(dataEdit))
//update lại trạng thái, để đóng modal
setEdit(false);
setDataEdit({})
}
/** close modal edit */
const closeEdit = ()=>{
setEdit(false);
setDataEdit({})
}
/** delete comment */
const removeComment = (item)=>dispatch(remove(item));
return (
<div className={styles.container}>
<div className={styles.boxcomment}>
<label>Body</label>
<textarea rows={5} cols={5} placeholder="Comment...!" onChange={(e)=>setBody(e.target.value)}></textarea>
<button onClick={()=>addComment()}>Send Comment</button>
</div>
<div className={styles.listComments}>
<h3>Comments : {data.length} comment</h3>
<ul>
{
data.length>0 && data.map((item)=>{
return (
<li key={item._id}>
<p className={styles.info}>{item._cmt}</p>
<div className={styles.control}>
<span onClick={()=>removeComment(item)}>remove</span>
<span onClick={()=>editComment(item)}>edit</span>
</div>
</li>
)
})
}
</ul>
</div>
<div className={styles.modal} style={{"display":edit?"block":"none"}}>
<label>Edit</label>
<span className={styles.close} onClick={()=>closeEdit()}>X</span>
<input type="text" value={dataEdit?._id} />
<textarea onChange={(e)=>setDataEdit({...dataEdit,_cmt:e.target.value})} value={dataEdit?._cmt}></textarea>
<button onClick={()=>updateComment()}>Update</button>
</div>
</div>
)
}
Đoạn code bên trên mình có giải thích một số chổ, bạn có thể xem nó, đồng thời ta cần hiển thị dữ liệu data ra khi có một dữ liệu được thêm vào
data.length>0 && data.map((item)=>{
return (
<li key={item._id}>
<p className={styles.info}>{item._cmt}</p>
<div className={styles.control}>
<span onClick={()=>removeComment(item)}>remove</span>
<span onClick={()=>editComment(item)}>edit</span>
</div>
</li>
)
})
Ta cần bắt sự kiện edit dữ liệu, ta cần cài đặt modal edit như sau:
<div className={styles.modal} style={{"display":edit?"block":"none"}}>
<label>Edit</label>
<span className={styles.close} onClick={()=>closeEdit()}>X</span>
<input type="text" value={dataEdit?._id} />
<textarea onChange={(e)=>setDataEdit({...dataEdit,_cmt:e.target.value})} value={dataEdit?._cmt}></textarea>
<button onClick={()=>updateComment()}>Update</button>
</div>
Cũng khá đơn giản phải không nào kaka, để xử lý giao diện cho dễ nhìn ta cần phải setup file css nhé, comment.module.css
Create comment.module.css file
*{
margin:0;padding:0;
}
.container{
width: 600px;
margin:20px auto;
padding: 10px;
box-sizing: border-box;
background-color: #ccc;
border-radius: 10px;
position: relative;
}
.boxcomment{
width: 100%;
}
.boxcomment label{
font-weight: bold;
display: block;
padding:10px 0;
text-align: left;
}
.boxcomment textarea{
width: 100%;
padding: 10px;
box-sizing: border-box;
border-radius: 10px;
border:none;
background-color: #fff;
}
.boxcomment button{
padding: 8px;
background-color: green;
color:#fff;
border:none;
}
.listComments h3{
padding:5px 0;
color:red;
text-align: left;
}
.listComments ul li{
margin:5px 0px;
list-style: none;
background-color: #fff;
padding: 3px;
border-radius: 5px;
display: flex;
flex-direction: row;
justify-content: space-between;
}
.listComments ul li p.info{
font-size: 14px;
line-height: 25px;
text-align: left;
width: 70%;
}
.listComments ul li .control span{
padding:0 5px;
display: inline-block;
margin:0 5px;
cursor: pointer;
border-radius: 10px;
font-size: 13px;
}
.listComments ul li .control span:first-child{
background-color: red;
color:#000;
}
.listComments ul li .control span:last-child{
background-color: yellow;
color:#000;
}
.modal{
position: absolute;
top:50%;
left:50%;
transform: translate(-50%,-50%);
width: 300px;
margin: 0 auto;
padding:10px;
box-sizing: border-box;
background-color: #787;
border-radius: 10px;
display: none;
}
.modal label{
display: block;
font-weight: bold;
font-size: 15px;
text-align: left;
}
.modal input{
width: 100%;
padding:10px;
box-sizing: border-box;
margin:5px 0;
}
.modal textarea{
width: 100%;
padding:10px;
box-sizing: border-box;
}
.modal button{
width: 100%;
border:none;
padding:8px;
box-sizing: border-box;
background-color: greenyellow;
}
.modal .close{
padding: 1px;
width: 30px;
display: block;
background: red;
box-sizing: border-box;
font-weight: bold;
position: absolute;
right: 10px;
top: 5px;
cursor: pointer;
}
Add commentReduce trong Store.js
import { configureStore } from '@reduxjs/toolkit';
//import commentSlice.js của ta
import commentReducer from '../features/comment/commentSlice';
import counterReducer from '../features/counter/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
comment: commentReducer
},
});
Okay vậy ta có thể sử dụng được rồi, ta sẽ gọi Comment.js trong App.js như sau:
import React from 'react';
import Comment from './features/comment/Comment'
import './App.css';
function App() {
return (
<div className="App">
<Comment />
</div>
);
}
export default App;
Vậy là xong phần sử dụng redux-toolkit, chạy nó thôi
npm start
Ví dụ mình làm ở trên cũng khá đơn giản, các bạn có thể phát triển nhé