Redux-Toolkit CRUD example with React Hooks

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é

Bài Viết Liên Quan

Messsage

Ủng hộ tôi bằng cách click vào quảng cáo. Để tôi có kinh phí tiếp tục phát triển Website!(Support me by clicking on the ad. Let me have the money to continue developing the Website!)