Skip to content

Commit 71bcdfc

Browse files
committed
feat:use zustand (#16)
* feat: update * feat: FormModal update * feat: use zustand
1 parent a561b9f commit 71bcdfc

File tree

15 files changed

+111
-128
lines changed

15 files changed

+111
-128
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ react-typescript 后台管理系统项目模版、内置动态嵌套路由、数
66
![Static Badge](https://img.shields.io/badge/tailwindcss-black?logo=tailwindcss&style=for-the-badge)
77
![Static Badge](https://img.shields.io/badge/antdesign-black?logo=antdesign&style=for-the-badge)
88
![Static Badge](https://img.shields.io/badge/swr-black?logo=swr&style=for-the-badge)
9-
![Static Badge](https://img.shields.io/badge/mobx-black?logo=mobx&style=for-the-badge)
109
![Static Badge](https://img.shields.io/badge/webpack-black?logo=webpack&style=for-the-badge)
1110
![Static Badge](https://img.shields.io/badge/vite-black?logo=vite&style=for-the-badge)
1211
![Static Badge](https://img.shields.io/badge/rsbuild-black?style=for-the-badge)
@@ -29,7 +28,7 @@ react-typescript 后台管理系统项目模版、内置动态嵌套路由、数
2928
- swr
3029
- tailwindcss
3130
- ant-design
32-
- mobx
31+
- zustand
3332

3433
#### 打包/开发相关
3534

package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,12 @@
7070
"axios": "^1.6.8",
7171
"classnames": "^2.5.1",
7272
"core-js": "^3.36.0",
73-
"mobx": "^6.12.0",
74-
"mobx-react-lite": "^3.4.3",
7573
"nanoid": "^4.0.2",
7674
"react": "^18.2.0",
7775
"react-dom": "^18.2.0",
7876
"react-router-dom": "^6.22.3",
79-
"swr": "^2.3.3"
77+
"swr": "^2.3.3",
78+
"zustand": "^5.0.5"
8079
},
8180
"lint-staged": {
8281
"*.{js,jsx,ts,tsx}": [

src/components/ErrorBoundary/index.tsx

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { Component, ReactElement } from "react";
22

3-
// import { notification } from "antd";
4-
53
class ErrorBoundary extends Component<{
64
children: ReactElement;
75
errComponent: ReactElement;
@@ -10,18 +8,6 @@ class ErrorBoundary extends Component<{
108
hasError: false,
119
};
1210

13-
// componentDidMount() {
14-
// addEventListener(
15-
// "error",
16-
// err => {
17-
// notification.error({
18-
// message: "ErrorBoundary 异常报错 ===>" + err.message,
19-
// });
20-
// },
21-
// false
22-
// );
23-
// }
24-
2511
static getDerivedStateFromError(error: any) {
2612
return { hasError: true, errMsg: error };
2713
}

src/components/FormList/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ const FormList = (props: FormListProps) => {
115115
name={e.name}
116116
label={e.label}
117117
extra={e.extra}
118-
rules={[e.rule]}
119118
hidden={!(e.visible ?? true)}
119+
rules={e.rule ? [e.rule] : undefined}
120120
valuePropName={e.valuePropName ? e.valuePropName : e.type === "switch" ? "checked" : "value"}
121121
initialValue={e.type === "radio" ? e.options?.[0].value : e.type === "switch" ? true : undefined}
122122
{...e.formItemProps}

src/components/FormModal/index.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,27 @@ import { FormInstance, Modal, ModalProps } from "antd";
44
import FormList, { FormListProps } from "../FormList";
55

66
interface FormModalProps
7-
extends Pick<ModalProps, "open" | "title" | "classNames" | "className" | "maskClosable" | "onCancel" | "okButtonProps">,
7+
extends Pick<ModalProps, "open" | "width" | "title" | "classNames" | "className" | "maskClosable" | "onCancel" | "okButtonProps">,
88
Pick<FormListProps, "form" | "itemInfo" | "wrapperCol" | "labelCol" | "initialValues" | "stageValues" | "onOk" | "onForm" | "onValuesChange"> {
99
noFooter?: boolean;
1010
}
1111

1212
const FormModal = (props: FormModalProps) => {
13-
const { open, title, noFooter, okButtonProps, className, classNames, maskClosable = true, onCancel, wrapperCol = 21, labelCol = 3, onForm, ...resetProps } = props;
13+
const {
14+
open,
15+
width = 880,
16+
title,
17+
noFooter,
18+
className,
19+
classNames,
20+
okButtonProps,
21+
wrapperCol = 21,
22+
labelCol = 3,
23+
maskClosable = true,
24+
onForm,
25+
onCancel,
26+
...resetProps
27+
} = props;
1428

1529
const formInstance = useRef<FormInstance<any> | null>(null);
1630

@@ -21,9 +35,9 @@ const FormModal = (props: FormModalProps) => {
2135

2236
return (
2337
<Modal
24-
width={880}
2538
open={open}
2639
okText="确定"
40+
width={width}
2741
title={title}
2842
destroyOnHidden
2943
cancelText="取消"

src/components/UploadModal/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { memo, useState } from "react";
22
import { InboxOutlined } from "@ant-design/icons";
3-
import { notification, Upload } from "antd";
3+
import { message, Upload } from "antd";
44
import type { UploadProps } from "antd";
55

66
import FormModal from "../FormModal";
@@ -75,7 +75,7 @@ const UploadModal = ({
7575
}}
7676
onOk={() => {
7777
if (!file.length) {
78-
notification.error({ message: "请上传文件!" });
78+
message.error("请上传文件!");
7979
return;
8080
}
8181

src/formIten.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ declare interface FormItem {
33
label?: string | React.ReactNode;
44
placeholder?: string;
55
initialValue?: unknown;
6-
rule?: import("antd").FormItemProps["rules"][number];
6+
rule?: import("antd").FormRule;
77
hide?: boolean;
88
visible?: boolean;
99
disable?: boolean;

src/layout/header.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,30 @@ import { Avatar, Dropdown, Layout } from "antd";
33
import type { MenuProps } from "antd";
44
import classnames from "classnames";
55
import { useNavigate } from "react-router-dom";
6+
import { useShallow } from "zustand/react/shallow";
67

78
import dark_img from "&src/assets/images/dark.svg";
89
import light_img from "&src/assets/images/light.svg";
9-
import store from "&src/store/store";
10+
import useRootStore from "&src/store";
1011
import lessStyle from "./index.module.less";
1112

1213
const { Header } = Layout;
13-
const { setLogin, setDarkMode } = store;
1414

15-
const MenuHeader = ({ tabId, tabList, darkMode, userInfo }: { tabId: string; tabList: MenuItem[]; darkMode: boolean; userInfo?: any }) => {
15+
interface MenuHeaderProps {
16+
tabId: string;
17+
tabList: MenuItem[];
18+
}
19+
20+
const MenuHeader = ({ tabId, tabList }: MenuHeaderProps) => {
1621
const navigate = useNavigate();
22+
const { userInfo, darkMode, setLogin, setDarkMode } = useRootStore(
23+
useShallow(store => ({
24+
darkMode: store.darkMode,
25+
userInfo: store.userInfo,
26+
setLogin: store.setLogin,
27+
setDarkMode: store.setDarkMode,
28+
}))
29+
);
1730

1831
const items: MenuProps["items"] = [
1932
{

src/layout/index.tsx

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { useMemo } from "react";
22
import { ConfigProvider, Layout, theme } from "antd";
3-
import { observer } from "mobx-react-lite";
43
import { Link, useLocation } from "react-router-dom";
54

65
import BreadCrumb from "&src/components/BreadCrumb";
76
import { COLOR_PRIMARY, SPLIT_FLAG } from "&src/config";
8-
import MobxContext from "&src/store/context";
9-
import store from "&src/store/store";
7+
import useRootStore, { useGetRouterConfig } from "&src/store";
108
import MenuHeader from "./header";
119
import SiderCom from "./sider";
1210

@@ -67,15 +65,10 @@ function menuHandle(routerMenu: MenuItem[] = [], pathname: string): [string, str
6765
return [tabId, menuId, sideMenu];
6866
}
6967

70-
const AppLayout = observer(({ children }: { children: React.ReactNode }) => {
68+
const AppLayout = ({ children }: { children: React.ReactNode }) => {
7169
const { pathname } = useLocation();
72-
const {
73-
isLogin,
74-
darkMode,
75-
userInfo,
76-
routeAndMenu: { routerMenu },
77-
routerPathMapping,
78-
} = store;
70+
const darkMode = useRootStore(store => store.darkMode);
71+
const { routerMenu, routerPathMapping } = useGetRouterConfig();
7972

8073
// 获取当前选中 menu ID
8174
const [tabId, menuId, sideMenu] = useMemo(() => {
@@ -91,7 +84,7 @@ const AppLayout = observer(({ children }: { children: React.ReactNode }) => {
9184
<div className={darkMode ? "dark" : ""}>
9285
<ConfigProvider theme={currentThem}>
9386
<Layout>
94-
<MenuHeader tabId={tabId} tabList={routerMenu} darkMode={darkMode} userInfo={userInfo} />
87+
<MenuHeader tabId={tabId} tabList={routerMenu} />
9588

9689
<Layout className="h-[calc(100vh-3.5rem)] overflow-hidden">
9790
{sideMenu.length ? <SiderCom selectKey={menuId} menu={sideMenu} /> : null}
@@ -100,16 +93,14 @@ const AppLayout = observer(({ children }: { children: React.ReactNode }) => {
10093
<Content className="m-3 mb-0 mt-0">
10194
<BreadCrumb routerPath={routerPathMapping} />
10295

103-
<div className="h-[calc(100%-4.5rem)] overflow-auto">
104-
<MobxContext.Provider value={{ isLogin, userInfo }}>{children}</MobxContext.Provider>
105-
</div>
96+
<div className="h-[calc(100%-4.5rem)] overflow-auto">{children}</div>
10697
</Content>
10798
</Layout>
10899
</Layout>
109100
</Layout>
110101
</ConfigProvider>
111102
</div>
112103
);
113-
});
104+
};
114105

115106
export default AppLayout;

src/pages/login/index.tsx

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,40 @@
1-
import { useEffect, useState } from "react";
1+
import { memo, useEffect, useState } from "react";
22
import { Button, Card, Form, Input, Layout } from "antd";
33
import { useNavigate } from "react-router-dom";
4+
import { useShallow } from "zustand/react/shallow";
45

56
import { loginReq } from "&src/api/account";
67
import { LOCAL_DYNAMIC_ROUTER, LOCAL_TOKEN, LOCAL_USER_INFO } from "&src/config";
78
import GLOBAL_ROUTERS from "&src/router/config";
8-
import store from "&src/store/store";
9+
import useRootStore from "&src/store";
910
import type { AccountApi } from "&src/types/api";
1011
import { getLocalStorage } from "&src/utils";
1112
import lessStyle from "./index.module.less";
1213

13-
const { setLogin, setDynamicRoutes } = store;
14-
1514
const Login = () => {
1615
const navigate = useNavigate();
16+
const { setLogin, setDynamicRoutes } = useRootStore(useShallow(store => ({ setLogin: store.setLogin, setDynamicRoutes: store.setDynamicRoutes })));
17+
1718
const [loading, loadingHandle] = useState(false);
1819

1920
const onFinish = async (values: AccountApi.Login) => {
2021
loadingHandle(true);
2122
const res = await loginReq(values);
22-
2323
localStorage.setItem(LOCAL_TOKEN, res.data.token);
2424
localStorage.setItem(LOCAL_USER_INFO, JSON.stringify(res.data.userInfo));
2525
localStorage.setItem(LOCAL_DYNAMIC_ROUTER, JSON.stringify(GLOBAL_ROUTERS.APP_PAGE));
2626

2727
// 设置登录态 用户信息 动态路由配置
2828
setLogin({ login: true, userInfo: res.data.userInfo });
2929
setDynamicRoutes(GLOBAL_ROUTERS.APP_PAGE);
30-
3130
loadingHandle(false);
3231
navigate("/");
3332
};
3433

3534
useEffect(() => {
36-
if (getLocalStorage(LOCAL_TOKEN)) navigate("/");
35+
if (getLocalStorage(LOCAL_TOKEN)) {
36+
navigate("/");
37+
}
3738
}, [navigate]);
3839

3940
return (
@@ -65,4 +66,4 @@ const Login = () => {
6566
);
6667
};
6768

68-
export default Login;
69+
export default memo(Login);

0 commit comments

Comments
 (0)