使用vite+react+ts+Ant Design开发后台管理项目(二)
前言
本文将引导开发者从零基础开始,运用、react、react-router、react-redux、Ant Design、less、tailwindcss、axios等前沿技术栈,构建一个高效、响应式的后台管理系统。通过详细的步骤和实践指导,文章旨在为开发者揭示如何利用这些技术工具,从项目构思到最终实现的全过程,提供清晰的开发思路和实用的技术应用技巧。
项目gitee地址:lbking666666/enqi-admin
本系列文章:
- 使用vite+react+ts+Ant Design开发后台管理项目(一)
- 使用vite+react+ts+Ant Design开发后台管理项目(二)
使用redux
上一章布局组件拆分前组件侧边栏和头部需要有交互,根据一个响应式的变量collapsed来进行交互的,目前已经把这两部分拆分到了两个子组件header.tsx和sider.tsx中,此时需要引入redux来对状态进行管理。
引入redux和 @reduxjs/toolkit
# 如果你使用 npm:
npm install react-redux @reduxjs/toolkit -S
# 或者你使用 Yarn:
yarn add react-redux @reduxjs/toolkit
为什么使用 Redux Toolkit
Redux Toolkit 是官方推荐的编写 Redux 逻辑的方法。它围绕 Redux 核心,并包含我们认为对于构建 Redux 应用必不可少的软件包和功能。Redux Toolkit 简化了大多数 Redux 任务,防止了常见错误,并使编写 Redux 应用程序更加容易。
无论你是一个想要开发第一个 Redux 应用的新手,还是想要简化已有应用经验老道的老手,Redux Toolkit 都能帮你写出更好的 Redux 代码。
创建store文件
首先在src文件夹下创建store文件夹,新建一个index.ts文件
//store/index.ts
import { configureStore } from "@reduxjs/toolkit";
//处理eslint报错
/* eslint-disable @typescript-eslint/no-unused-vars */
const store = configureStore({
reducer: {
},
});
// 从 store 本身推断 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>;
// 推断类型:{posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
export default store;
创建reducer
在store文件夹下新建reducers文件夹,新增一个文件global.ts
//global.ts
import { createSlice } from "@reduxjs/toolkit";
import type { RootState } from "@/store/index.ts";
// 定义初始 state 的类型
interface GlobalState {
collapsed: boolean;
}
// 使用该类型定义初始 state
const initialState: GlobalState = {
collapsed: false
};
// 创建 slice
export const globalSlice = createSlice({
name: "global",// 名称
initialState,// 初始 state
reducers: {
// 定义 reducer 函数,该函数接受 state 和 action 作为参数
setCollapsed: (state) => {
// 更新 state
state.collapsed = !state.collapsed;
},
},
});
// 为每个 case reducer 函数生成 Action creators
export const { setCollapsed } = globalSlice.actions;
// selectors 等其他代码可以使用导入的 `RootState` 类型
export const selectCollapsed = (state: RootState) => state.global.collapsed;
// 导出 reducer
export default globalSlice.reducer;
使用 Hooks 类型
尽管你可以将 RootState
和 AppDispatch
类型导入每个组件, 更好的方式是创建 useDispatch
和 useSelector
钩子的类型定义,以便在你的应用程序中使用
- 对于
useSelector
,它不需要你每次输入(state: RootState)
- 对于
useDispatch
,默认的 Dispatch 类型不知道 thunk 。为了正确调度 thunk ,你需要使用 store 中包含 thunk 中间件类型的特定自定义AppDispatch
类型,并将其与useDispatch
一起使用。添加一个预先输入的useDispatch
钩子可以防止你忘记在需要的地方导入AppDispatch
。
由于这些是实际变量,而不是类型,因此将它们定义在单独的文件中很重要,而不是 store 设置文件。这允许你将它们导入到需要使用挂钩的任何组件文件中,并避免潜在的循环导入依赖问题。
定义 Hooks 类型
在src文件夹下新增hooks文件夹,新增文件UseGlobal.hooks.ts
//UseGlobal.hooks
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from '@/store/index';
// 在整个应用程序中使用,而不是简单的 `useDispatch` 和 `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
引入globalReducer
修改store文件夹下的index.ts
//store/index.ts
import { configureStore } from "@reduxjs/toolkit";
import globalReducer from "./reducers/global";
//处理eslint报错
/* eslint-disable @typescript-eslint/no-unused-vars */
const store = configureStore({
reducer: {
global: globalReducer,
},
});
// 从 store 本身推断 `RootState` 和 `AppDispatch` 类型
export type RootState = ReturnType<typeof store.getState>;
// 推断类型:{posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch;
export default store;
在组件中使用
上一章中的左侧组件和头部组件中有一个响应式变量collapsed,现在可以使用redux状态来处理,根据Ant Design的代码和组件拆分分析,两个组件都需要使用这个collapsed状态所以放在layout文件夹下的index.tsx中获取当前的collapsed值,然后通过给组件传参的形式同步两个组件的状态
1.布局组件改造
修改layout文件夹下的index.tsx内容
//layout/index.tsx
import React from "react";
import { Layout } from "antd";
import { useAppSelector} from '@/hooks/UseGlobal.hooks';
import { selectCollapsed } from "@/store/reducers/global";
import AppHeader from "./header";
import AppSider from "./sider";
import AppMain from "./main";
const App: React.FC = () => {
// 获取全局状态 collapsed 可以使用以下两种方式中的一种
//const collapsed:boolean = useAppSelector((state) => state.global.collapsed);
const collapsed: boolean = useAppSelector(selectCollapsed);
return (
<Layout className="app-layout ">
<AppSider collapsed={collapsed} />
<Layout>
<AppHeader collapsed={collapsed} />
<AppMain />
</Layout>
</Layout>
);
};
export default App;
2.侧边组件改造
修改layout文件夹下的sider.tsx
//layout/sider.tsx
import React from "react";
import {
UploadOutlined,
UserOutlined,
VideoCameraOutlined,
} from "@ant-design/icons";
import { Layout, Menu } from "antd";
const { Sider } = Layout;
interface AppSiderProps {
collapsed: boolean;
}
const AppSider: React.FC<AppSiderProps> = ({ collapsed }) => {
return (
<Sider trigger={null} collapsible collapsed={collapsed}>
<div className="demo-logo-vertical" />
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={["1"]}
items={[
{
key: "1",
icon: <UserOutlined />,
label: "nav 1",
},
{
key: "2",
icon: <VideoCameraOutlined />,
label: "nav 2",
},
{
key: "3",
icon: <UploadOutlined />,
label: "nav 3",
},
]}
/>
</Sider>
);
};
export default AppSider;
3.头部组件改造
修改layout文件夹下的header.tsx
//layout/header.tsx
import React from "react";
import { Button, Layout, theme } from "antd";
import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons";
const { Header } = Layout;
interface AppSiderProps {
collapsed: boolean;
}
const AppHeader: React.FC<AppSiderProps> = ({ collapsed }) => {
const {
token: { colorBgContainer },
} = theme.useToken();
return (
<Header style={{ padding: 0, background: colorBgContainer }}>
<Button
type="text"
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
style={{
fontSize: "16px",
width: 64,
height: 64,
}}
/>
</Header>
);
};
export default AppHeader;
4.添加事件
如上图所示点击红框的按钮需要做到伸缩左侧的侧边栏,固需要在这里添加事件
代码如下
//layout/header.tsx
import React from "react";
import { Button, Layout, theme } from "antd";
import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons";
import { useAppDispatch } from '@/hooks/UseGlobal.hooks';
import { setCollapsed } from "@/store/reducers/global";
const { Header } = Layout;
interface AppSiderProps {
collapsed: boolean;
}
const AppHeader: React.FC<AppSiderProps> = ({ collapsed }) => {
const {
token: { colorBgContainer },
} = theme.useToken();
const dispatch = useAppDispatch();
const handleCollapsed = () => {
//更新全局状态 collapsed
dispatch(setCollapsed());
};
return (
<Header style={{ padding: 0, background: colorBgContainer }}>
<Button
type="text"
icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
style={{
fontSize: "16px",
width: 64,
height: 64,
}}
onClick={handleCollapsed}
/>
</Header>
);
};
export default AppHeader;
查看效果,点击按钮左侧边栏可以伸缩
后续
本篇文章为项目引入了redux和怎么在项目中使用做了说明,代码已经同步到了gitee仓库,下一篇会丰富头部组件,使用redux增加主题风格配置和左侧菜单抽离为单独组件根据不同的菜单点击进入不同组件