react redux Toolkit 分组更推荐

bash 复制代码
import { message } from 'antd';
import service from '@/utils/request2';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import Cookies from 'js-cookie';
import { Result } from '@/interface/ResultInterface';


interface userInterface {
  token: string;
  username: string;
  isAdmin: string;
  id: string;
}




// 异步Thunk:登录并获取用户信息
export const loginAndFetchUser = createAsyncThunk(
  'auth/loginAndFetchUser',
  async (loginData: any, { rejectWithValue }) => {
    try {
      // 1. 调用登录接口
      const loginResponse: Result<userInterface> = await service.post('/auth/login', loginData);
      const { token, username, isAdmin, id } = loginResponse.data;

      // 2. 将token存储到localStorage和Redux state

      // 3. 使用token获取用户详细信息
      // const userInfoResponse = await getUserProfile(token);
      return { token, username, isAdmin, id };
    } catch (error) {
      return rejectWithValue(error.response.data);
    }
  }
);
// 2. 提供初始状态,并明确指定其类型
const initialState: userInterface = {
  token: Cookies.get('header-access-token-dianchi') || null,
  username: Cookies.get('username') || null,
  isAdmin: Cookies.get('isAdmin') || null,
  id: Cookies.get('id') || null,
};
const userStore = createSlice({
  name: 'user',
  initialState,
  reducers: {
    logout: (state) => {
      state.token = null;
      state.username = null;
      Cookies.remove('username');
      Cookies.remove('header-access-token-dianchi');
      Cookies.remove('isAdmin');
      Cookies.remove('id');
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(loginAndFetchUser.pending, (state) => { })
      .addCase(loginAndFetchUser.fulfilled, (state, action) => {
        state.token = action.payload.token;
        state.username = action.payload.username;
        state.isAdmin = action.payload.isAdmin.toString();
        state.id = action.payload.id.toString();


        Cookies.set('header-access-token-dianchi', state.token);
        Cookies.set('username', state.username);
        Cookies.set('isAdmin', state.isAdmin);
        Cookies.set('id', state.id);
      })
      .addCase(loginAndFetchUser.rejected, (state, action) => { });
  },
});
//解构出action对象的函数
export const { logout } = userStore.actions;
//获取reducer函数
const userReducer = userStore.reducer;
export default userReducer;
bash 复制代码
import { MenuItem } from '@/types/MenuItem.type';
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

export interface MenuState {
  menuList: MenuItem[]; // menuList 应该是 MenuItem 类型的数组
  // 如果你有其他状态字段,也在这里定义,例如:
  isHasMenu: boolean;
}

// 2. 提供初始状态,并明确指定其类型
const initialState: MenuState = {
  menuList: [], // 初始为空数组,符合 MenuItem[] 类型
  isHasMenu: false,
};
const menuStore = createSlice({
  name: 'menu',
  initialState,
  reducers: {
    setIsHasMenu(state: MenuState) {
      state.isHasMenu = true;
    },
    // 示例1:设置整个菜单列表]
    setMenuList(state: MenuState, action: PayloadAction<MenuItem[]>) {
      state.menuList = action.payload;
    },
    // 示例2:添加单个菜单项
    addMenuItem(state: MenuState, action: PayloadAction<MenuItem>) {
      state.menuList.push(action.payload);
    },
    // 示例3:根据ID移除菜单项
    removeMenuItem(state: MenuState, action: PayloadAction<string>) {
      // 假设ID是字符串类型
      state.menuList = state.menuList.filter((item: MenuItem) => item.path !== action.payload);
    },
  },
});
//解构出action对象的函数
const { setMenuList, addMenuItem, removeMenuItem,setIsHasMenu } = menuStore.actions;
//获取reducer函数
const menuReducer = menuStore.reducer;
export { setIsHasMenu,setMenuList, addMenuItem, removeMenuItem };
export default menuReducer;
bash 复制代码
import { createSlice, PayloadAction } from '@reduxjs/toolkit';

export interface ThemeState {
  theme: 'light' | 'dark';
}

// 从 localStorage 读取主题设置,默认为 light
const getInitialTheme = (): 'light' | 'dark' => {
  const savedTheme = localStorage.getItem('theme');
  return (savedTheme === 'dark' || savedTheme === 'light') ? savedTheme : 'light';
};

const initialState: ThemeState = {
  theme: getInitialTheme()
};

const themeSlice = createSlice({
  name: 'theme',
  initialState,
  reducers: {
    toggleTheme: (state) => {
      state.theme = state.theme === 'light' ? 'dark' : 'light';
      localStorage.setItem('theme', state.theme);
      // 更新 document 的 data-theme 属性
      document.documentElement.setAttribute('data-theme', state.theme);
    },
    setTheme: (state, action: PayloadAction<'light' | 'dark'>) => {
      state.theme = action.payload;
      localStorage.setItem('theme', state.theme);
      // 更新 document 的 data-theme 属性
      document.documentElement.setAttribute('data-theme', state.theme);
    }
  }
});

// 导出 actions
export const { toggleTheme, setTheme } = themeSlice.actions;

// 导出 reducer
const themeReducer = themeSlice.reducer;
export default themeReducer;
bash 复制代码
import { configureStore } from '@reduxjs/toolkit'
import counterReducer from './slice/counterSlice';
import menuReducer from './slice/menuSlice';
import userReducer from './slice/userSlice';
import themeReducer from './slice/themeSlice';

const store = configureStore({
    reducer: {
        counterReducer: counterReducer,
        menuReducer:menuReducer,
        userReducer:userReducer,
        themeReducer:themeReducer,
    }
})
export type AppDispatch = typeof store.dispatch; // 导出 Dispatch 类型,用于异步 Action
export default store;

使用

bash 复制代码
import React, { useState } from 'react';
import { Form, Input, Button, message } from 'antd';
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import './index.css';   // 样式见下方
import { useNavigate } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { loginAndFetchUser } from '@/store/slice/userSlice';
import { useSelector } from 'react-redux';
const Login = () => {
  const [loading, setLoading] = useState(false);
  const navigate = useNavigate();
  const dispatch = useDispatch<any>();
  const theme = useSelector((state: any) => state.themeReducer.theme);
  const onFinish = async ({ account, password }) => {
    let params = {
      account: account,
      password,
    };
    try {
      try {
        await dispatch(loginAndFetchUser(params)).unwrap();
        navigate('/');
        // 登录成功后的跳转逻辑在下面的useEffect中处理
      } catch (error) {
        // 错误信息已在Redux中存储,这里可以显示错误提示
        console.error('Login failed:', error);
      }
    } catch (error) {
      navigate('/');
    }
  };

  return (
    <div className="login-wrapper">
      <div className="login-card">
        <h1 className="login-title">电池管理项目</h1>
        <Form
          name="login"
          layout="vertical"
          onFinish={onFinish}
          autoComplete="off"
          initialValues={{
            account: 'admin',
            password: '123456',
          }}
        >
          <Form.Item
            name="account"
            rules={[{ required: true, message: '请输入账户' }]}
          >
            <Input
              prefix={<UserOutlined />}
              placeholder="账户 / Email"
              size="large"
            />
          </Form.Item>

          <Form.Item
            name="password"
            rules={[{ required: true, message: '请输入密码' }]}

          >
            <Input.Password
              prefix={<LockOutlined />}
              placeholder="密码"
              size="large"
            />
          </Form.Item>

          <Form.Item>
            <Button
              type="primary"
              htmlType="submit"
              loading={loading}
              size="large"
              block
              className="login-btn"
            >
              立 即 登 录
            </Button>
          </Form.Item>
        </Form>
      </div>
    </div>
  );
};

export default Login;
相关推荐
Csvn7 小时前
OpenSpec 详细使用教程
前端
之歆8 小时前
Day19_LESS 完全指南——从入门到工程实践
前端·css·less
云水一下8 小时前
HTML5 从入门到精通:实战收官——从零搭建完整静态网站,综合运用所有知识
前端·html5
不总是9 小时前
Windows 系统 Node.js 免安装版(zip)安装与配置教程(2026 最新)
前端·windows·node.js
冬奇Lab9 小时前
每日一个开源项目(第105篇):Twenty - 跳出 Salesforce 的圈套,定义现代开源 CRM
前端·后端·开源
zhangyao94033010 小时前
开发pc端时,表格的高度怎么设置才能铺满页面
前端·javascript·elementui
XinZong10 小时前
实测OpenClaw虾淘:全民工具AI时代,冷门非工具类的Skill还能出圈吗?
javascript
kjs--10 小时前
浏览器书签执行脚本
前端
烛衔溟10 小时前
TypeScript 类的类型 —— 作为类型使用
javascript·ubuntu·typescript
之歆10 小时前
Day16_JavaScript 轮播图与事件工程实战(下篇)
服务器·开发语言·前端·javascript·网络·性能优化