什麼時候要用RTK、Zustand

2025/08/20

介紹大專案如何運用RTK、Zustand各司其職
什麼時候要用RTK、Zustand

RTK: 全域狀態

一個app 只會有一個 snackbar 非常適合RTK全域管理,任何component、page 都可以直接呼叫

tsx
1// src/store/slices/snackbarSlice.ts
2import { createSlice } from "@reduxjs/toolkit";
3import { AlertColor } from "@mui/material";
4// const defaultDuration = 3000;
5const snackbarSlice = createSlice({
6  name: "snackbar",
7  initialState: {
8    open: false,
9    message: "",
10    severity: "success" as AlertColor,
11    autoHideDuration: 3000,
12  },
13  reducers: {
14    showSnackbar: (state, action) => {
15      state.open = true;
16      state.message = action.payload.message;
17      state.severity = action.payload.severity;
18      state.autoHideDuration =
19        action.payload.autoHideDuration === undefined
20          ? 3000
21          : action.payload.autoHideDuration;
22    },
23    closeSnackbar: (state) => {
24      state.open = false;
25    },
26  },
27});
28
29export const { showSnackbar, closeSnackbar } = snackbarSlice.actions;
30export default snackbarSlice.reducer;
31

Zustand: 單頁 page state

像是某個頁面的 Drawer 是否開啟,但unmount 的時候要 cleanup 不要佔記憶體

tsx
1// src/app/some page/_store/useMobileFilterDrawerStore.ts
2import { create } from "zustand";
3
4interface MobileFilterDrawerState {
5  isMobileFilterDrawerOpen: boolean;
6  open: () => void;
7  close: () => void;
8  toggle: () => void;
9}
10
11export const useMobileFilterDrawerStore = create<MobileFilterDrawerState>(
12  (set) => ({
13    isMobileFilterDrawerOpen: false,
14    open: () => set({ isMobileFilterDrawerOpen: true }),
15    close: () => set({ isMobileFilterDrawerOpen: false }),
16    reset: () => set({ isMobileFilterDrawerOpen: false }), // <-- 清空回初始狀態
17  })
18);
tsx
1// src/app/some page
2import { useEffect } from "react";
3import { useMobileFilterDrawerStore } from "@/app/somepage/_store/useMobileFilterDrawerStore";
4
5export default function SomeComponent() {
6  const { isMobileFilterDrawerOpen, open, close, reset } =
7    useMobileFilterDrawerStore();
8
9  // Component unmount 時 cleanup
10  useEffect(() => {
11    return () => {
12      reset(); // <-- 在離開頁面或元件unmount時清空
13    };
14  }, [reset]);
15
16  return (
17    <>
18      <button onClick={open}>Open Drawer</button>
19      <button onClick={close}>Close Drawer</button>
20      {isMobileFilterDrawerOpen && <div>Drawer Content</div>}
21    </>
22  );
23}
24