Redux

Trong dự án sẽ dùng redux để trao đổi dữ liệu giữa các component với nhau hoặc để lưu trữ state cho sử dụng cho việc khác

Base sẽ sử dụng redux toolkit để việc khai báo đỡ vất vả hơn

1. Khai báo

Tạo file với tên là Chức năng + Slice trong thư mục redux/slices. Ví dụ:

📦redux
 ┣ 📂slices
 ┃ ┣ 📜UserSlice.tsx
 ┃ ┣ 📜MenuSlice.tsx

Trong file UserSlice sẽ có nội dung như sau:

import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { IAccountInfo } from "../../types"
 
// Khai báo initValue
const initialState: IAccountInfo = {}
 
const UserSlice = createSlice({
  name: "user", //Nên đặt theo chức năng
  initialState, //Giá trị khởi tạo
  reducers: {
    //Tạo các action
    loginUser: (_, action: PayloadAction<IAccountInfo>) => {
      return action.payload // Trả về state trong store trong trường hơp này là dữ liệu truyền vào khi gọi dispatch
    },
    logoutUser: () => {
      return initialState
    },
  },
})
 
// Export các action ra để sử dụng
export const { loginUser, logoutUser } = UserSlice.actions
 
// Export reducer để import trong file redux/store.tsx
export default UserSlice.reducer

Trong file MenuSlice sẽ có nội dung như sau:

import { createSlice } from "@reduxjs/toolkit"
 
// Khai báo type của state
interface IMenuState {
  isOpen: boolean
}
 
// Khai báo initValue
const initialState: IMenuState = {
  isOpen: false,
}
 
const MenuSlice = createSlice({
  name: "menu", //Nên đặt theo chức năng
  initialState, //Giá trị khởi tạo
  reducers: {
    //Tạo các action
    openMenu: (state) => {
      state.isOpen = true //Sửa lại state
    },
    closeMenu: (state) => {
      state.isOpen = false //Sửa lại state
    },
    toggleMenu: (state) => {
      state.isOpen = !state.isOpen //Sửa lại state
    },
  },
})
 
// Export các action ra để sử dụng
export const { openMenu, closeMenu, toggleMenu } = MenuSlice.actions
 
// Export reducer để import trong file redux/store.tsx
export default MenuSlice.reducer

2. Thay đổi state trong store

Để thay đổi state trong store thì ta sẽ gọi action tương ứng khai báo trong reducer ra trong hàm dispatch

import { loginUser } from "../redux/slices/UserSlice" // Import action
import store from "@app/redux/store" // Import store
import { useDispatch } from "react-redux" // Import hook
 
export default function Login(): JSX.Element {
  const dispatch = useDispatch() // Khai báo sử dụng hook useDispatch
 
  const login = (loginData) => {
    loginMutation.mutate(loginData, {
      onSuccess: (res) => {
        dispatch(loginUser(res)) // Đây là cách dispatch dùng hook
        store.dispatch(loginUser(res)) // Đây là cách dispatch không dùng hook
      },
    })
  }
}

Lưu ý: Chỉ sử dụng cách dispatch không dùng hook nếu đoạn code xử lý không nằm trong React Component. Ví dụ như api/Fetcher.tsx

3. Lấy state trong store

Để lấy state trong store thì dùng useSelector hoặc getState từ store

import store from "@app/redux/store" // Import store
import { useSelector } from "react-redux" // Import hook
import { IRootState } from "@app/redux/reducers/RootReducer" // Import type của state
 
export default function Login(): JSX.Element {
  const user = useSelector((state: IRootState) => state.user) // Lấy state muốn sử dụng từ store ra
 
  const checkUserLoggedIn = () => {
    if (user.accessToken) {
      //Đây là cách lấy dùng hook
      return true
    }
    if (store.getState().user.accessToken) {
      //Đây là cách lấy không dùng hook
      return true
    }
    return false
  }
}

Lưu ý: Chỉ sử dụng cách lấy state không dùng hook nếu đoạn code xử lý không nằm trong React Component. Ví dụ như api/Fetcher.tsx