+3

Cách Làm Việc Với Redux - Redux-Toolkit

Bài viết này chủ yếu đưa đến các bạn mới học hoặc muốn ôn lại về redux và giới thiệu sơ về redux Toolkit ( Bài sau mình nói về nó ). Mục tiêu là mình viết để ôn lại kiến thức để khi quên có thể vào xem lại... Bài này cũng dễ mà dễ ngáo 🥲🥲🥲.

Redux là một thư viện JS dùng quản lý và cập nhật state của ứng dụng, là một pattern (khuôn mẫu - vì thế ae cứ làm theo - không cần thuộc làu đâu - làm nhiều tự bay vào đầu thôi) .

Thế vì sao lại sử dụng redux ? và Redux Toolkit nói riêng ?

alt

  • Quản lý Glabal state : thay vì ae tạo state ở component cha rồi truyền từ component này tới component con nhờ props thì sử dụng tool redux này ở đâu cũng lấy được state và chỉ tạo ra state ở reducer thôi. ( Câu này phỏng vấn có nha 😁😁😁)

  • Dễ dàng debug

  • Xử lý caching dữ liệu tử phía Server - không có tính năng này nên ae cần phải sử dụng một số cách như :

    • Sử dụng Middleware: Bạn có thể tạo một middleware để kiểm tra xem dữ liệu đã được cache hay chưa trước khi dispatch action gửi yêu cầu đến server. Nếu dữ liệu đã được cache, bạn có thể trả về dữ liệu đó mà không gửi yêu cầu đến server.

    • Sử dụng Local Storage hoặc Session Storage: Khi dữ liệu được nhận từ server, bạn có thể lưu trữ nó trong Local Storage hoặc Session Storage để sử dụng lại trong trường hợp cần thiết mà không cần gửi yêu cầu đến server một lần nữa.

    • Sử dụng Redux Persist: Redux Persist là một thư viện giúp bạn lưu trạng thái Redux vào local storage hoặc một nơi khác để giữ lại dữ liệu sau khi làm mới trang hoặc tắt/mở lại trình duyệt.

    • Cache Trong Reducer: Bạn có thể tự xây dựng logic caching trong reducer của mình. Khi nhận được dữ liệu từ server, bạn có thể lưu trữ nó trong reducer và kiểm tra nếu đã có dữ liệu trong reducer trước khi gửi yêu cầu đến server.

Redux Toolkit

  • Cũng đơn giản là thư viện của js và được bọc bên ngoài của redux Core
  • Sinh ra để giải quyết vấn đề của Redux Core :
    • Việc Cấu hình (config) redux Phúc tạp
    • Phải cài đặt thủ công nhiều packages để Redux có thể hoạt động hiệu quả
    • Redux yêu cầu rất nhiều boilerplate code (đoạn code lặp đi lặp lại)

Khi Nào Sử Dụng Đến Redux ?

  • Dự án có số lượng lớn State và các state được sử dụng ở nhiều nơi.

  • State được cập nhật thường xuyên.

  • Logic code cập nhật state phức tạp.

  • Ứng dụng có số lượng code trung bình hoặc lớn và có nhiều người làm chung.

  • Cần debug và muốn xem cách state được cập nhật tại bất kì khoảng thời gian nào.

Kiến Thức Bắt Buộc Khi Bạn Muốn Tìm Hiểu Về Redux.

  • HTML & CSS
  • Cú Pháp Và Tính Năng ES6
  • Kiến Thức React, State, Functional Component, React Hooks,....
  • Bất Đồng Bộ trong JavaScript (Async trong js)

Lưu Ý

  • Sử dụng thì khuyến khích sử dụng redux-Toolkit hơn nhé, nhưng muốn sử dụng được nó thì phải sử dụng được Redux trước đã. Nên là cứ từ từ thôi, nhảy cóc là ngáo nặng đấy.

  • Phía dưới mình sẽ nói rõ từng bước để viết code. nên cứ đọc từ từ.

Cài Đặt

npm install redux
# hoặc
yarn add redux

Cài đặt xong thì tạo một fonder với tên store

  • Tạo một file RootReducer.js => để chứa các reducer
  • Tạo một file index.js => chứa store
  • Tạo một file reducer.js => chứa reducer
  • Tạo một file action.js => các actions
  • Tạo một file constant.js => tạo để chứa các type trong actions để dễ quản lý code và sửa nhanh hơn.

Cách Hoạt Động và Code với Redux

alt

Trước mắt nhìn vào hình hiểu được thì bạn đã thành công hiểu redux rồi đó. Cùng ôn lại cách hoạt động của nó nhé. Mình sẽ đi từ Store trước.

  • Store là kho lưu trữ và bao bọc dự án của bạn. Chỉ một Store và trong Store có nhiều Reducer.
    • Trong file index.js

    • Chúng ta đã sử dụng createStore để tạo một Redux store và liên kết nó với reducer counterReducer. store.getState() được sử dụng để lấy trạng thái ban đầu của store.

    • Mấy này trên trang chủ có nhé anh em. Mình viết luôn cho anh em đỡ mất thời gian đi đọc lại.

import { createStore } from "redux";
import { rootReducer } from "./rootReducer";

// Tạo store và kết nối với reducer
export const store = createStore(
    rootReducer,
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    // thêm dòng này vào thì mới hoạt động được nha, createStore bị gạch ngang cũng không sao nhé ae, vì lỗi thời nên nó báo thế, đừng hoảng
);

  • Reducer là các kho con của mỗi loại dữ liệu mà bạn làm với dự án ( như người dùng là một reducer, sản phẩm là một reducer ). Lưu ý là không phải cái gì cũng lưu vào redux đâu nghe, không lạm dụng. Khi nào dự liệu thực sự cần sử dụng ở nhiều nơi thì hãy dùng thôi.

  • Để tạo một reducer : Trong file reducer.js

const initialState = {
  counter: 0
  user:{}
  cartPrd:[]
  // đây là nơi mình nói cho các reducer con ở phía trên
};

export const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'INCREMENT':
    //INCREMENT này ae nên qua constant.js để tạo một biến với chuỗi.
      return { ...state, counter: state.counter + 10 };
    case 'DECREMENT':
      return { ...state, counter: state.counter - 10 };
    default:
      return state;
  }
};

// Hoặc export default counterReducer;

state = initialState : initialState là giá trị khởi tạo đầu tiên cho kho chứa (0$ như hình).

Sử dụng switch case để biết được là đang là hành động gì, tăng hay giảm 10$ như trong hình.

Trong file rootReducer.js

  • File này chứa reducer bạn đã tạo ở trên, nó quản lý các reducer để có thể sử dụng hook gọi tới và lấy ra state bạn muốn. Thiếu thì nghỉ khỏe 😂😂😂.
import { combineReducers } from "redux";
import { counterReducer } from "./reducer";

export const rootReducer = combineReducers({
    counterReducer: counterReducer,
});

Tạo xong 2 cái đó thì làm sao dự án truy cập vào redux được? Vậy nên :

  • Bạn cần bao bọc dự án bởi store :
// App.js hoặc index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { Provider } from "react-redux";
import { store } from "./store/index";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
    <Provider store={store}>
        <App />
    </Provider>
);
reportWebVitals();

Setup xong rồi giờ sao lấy xài giờ?

  • Sử dụng hook useSelector() để lấy từ store và useDispatch() để bắn đi hành động :
  const Shoes = () => {
  // cách lấy từ store xuống.
  const { Carts, PrdList } = useSelector((rootReducer) => rootReducer);
  // cách để bắn đi hành động 
  const dispatch = useDispatch()
  // dispatch này bắn đi action mà bạn viết trong file action.js. còn logic thì theo dự án của bạn
  return <div>
                             <button
                                onClick={() => dispatch(handleAddPrd(product))}
                                className="btn btn-outline-info ml-2"
                            >
                                Mua
                            </button>
                   </div>
  }

Nói lại lần nữa nè:

  • Người dùng sẽ thao tác và chúng ta gắn dispatch để đẩy hành động của user đên store => trong hành động được đẩy đi sẽ bắc buộc có type và payload (type để store nhận biết được hành động này là gì và bắt case trong reducer, payload là dữ liệu cần gửi lên store để thực hiện logic nào đó của bạn)
  • Thực hiện logic ở reducer.js Bạn cần chú ý là sử dụng Es6 để thực hiện thay đổi trên state. Hãy tạo ra bản coppy và thực hiện logic trên bản coppy => Không được sử dụng hàm bất đồng bộ nào trong này => Thế nên mới sinh ra redux toolkit và redux Thunk. Hẹn ae bài sau . Dưới đây là code ví dụ về cách thực hiện và return
import { HANDLE_ADD_CART, HANDLE_QUANTITY } from "./constant";

const initialState = {
 cartsPrd: [],
};

export const shoesReducer = (state = initialState, action) => {
 switch (action.type) {
     case HANDLE_ADD_CART: {
         let newCarts = [...state.cartsPrd];

         const index = newCarts.findIndex(
             (prd) => prd.id === action.payload.id
         );
         if (index === -1) {
             newCarts.push({ ...action.payload, quantity: 1 });
         } else {
             newCarts[index].quantity += 1;
         }
         return { ...state, cartsPrd: newCarts };
     }
     case HANDLE_QUANTITY: {
         let newCarts = [...state.cartsPrd];
         const index = newCarts.findIndex(
             (prd) => prd.id === action.payload.id
         );
         newCarts[index].quantity =
             newCarts[index].quantity + action.payload.quantity;
         if (newCarts[index].quantity === 0) {
             newCarts = newCarts.filter(
                 (prd) => prd.id !== action.payload.id
             );
         }
         return { ...state, cartsPrd: newCarts };
     }
     default: {
         return state;
     }
 }
};
  • Hiểu về redux tườm tận thì bài sau ae nhẹ nhàng hơn nhiều.

Tạm Kết

  • Bài viết cũng dài rồi ae. mình sẽ viết về Redux Toolkit ở bài sau. hiểu thì tiếc gì +1 nha ae. Cho có động lực với 🥴🥴🥴

  • Có chỗ nào thắc mắc ae có thể tìm hiểu thẳng trên trang chủ của redux. Trang-Chủ-react-redux

alt

Thất hình này khác ở trên chỗ nào không anh em - Hẹn bài sau nghe - Dài quá rồi 🥲🥲🥲🥲🥲

  • Nói thêm tí nhé : là tài liệu thì cũng chỉ là từ trang này qua trang khác, bài này mình viết chủ yếu là muốn ae biết cách làm rồi quay lại tìm các tại liệu để hiểu sâu hơn về nó.
  • Mình trước kia cũng tìm kiếm nhiều lắm, nhưng mãi mới biết cách làm và code cho đúng thì là vấn đề lớn lắm anh em ạ. Mong bài này giúp được anh em nào đang giống mình khi xưa.
  • Chúc mọi người thành công !!! 🫠🫠🫠

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí