Skip to content

Commit d9ffe20

Browse files
authored
🦄 refactor: Optimize the Form component (#13)
* 🦄 refactor: Optimize the Form component Signed-off-by: Wanpan <wanpan96@163.com> * 🦄 refactor: Optimize the Form component Signed-off-by: Wanpan <wanpan96@163.com> * 🦄 refactor: It is possible that name equals null * 🦄 refactor: Optimize the Form component Signed-off-by: Wanpan <wanpan96@163.com> * ✨ feat: add useSwrData Signed-off-by: Wanpan <wanpan96@163.com> * feat: swr replace ahooks * feat: react-router-dom future flag * feat: mock sleep --------- Signed-off-by: Wanpan <wanpan96@163.com>
1 parent d19e757 commit d9ffe20

File tree

14 files changed

+341
-206
lines changed

14 files changed

+341
-206
lines changed

README-EN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ React typescript backend management system project template, built-in dynamic ne
2121
#### main dependency
2222

2323
- axios
24-
- ahooks
24+
- swr
2525
- tailwindcss
2626
- ant-design
2727
- mobx

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ react-typescript 后台管理系统项目模版、内置动态嵌套路由、数
2323
#### 主要依赖库
2424

2525
- axios
26-
- ahooks
26+
- swr
2727
- tailwindcss
2828
- ant-design
2929
- mobx

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
"dependencies": {
4848
"@ant-design/icons": "^5.3.4",
4949
"@unocss/reset": "^0.53.6",
50-
"ahooks": "^3.7.10",
5150
"antd": "^5.15.3",
5251
"axios": "^1.6.8",
5352
"classnames": "^2.5.1",
@@ -56,7 +55,8 @@
5655
"nanoid": "^4.0.2",
5756
"react": "^18.2.0",
5857
"react-dom": "^18.2.0",
59-
"react-router-dom": "^6.22.3"
58+
"react-router-dom": "^6.22.3",
59+
"swr": "^2.3.3"
6060
},
6161
"lint-staged": {
6262
"*.{js,jsx,ts,tsx}": [

src/api/setting.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ export const companyService = {
88
});
99
},
1010
list: (data: CompanyApi.ListReq) => {
11-
return request.send<CompanyApi.ListRes>("/company/list", "get", data);
11+
return request.send<CompanyApi.ListRes>("/company/list", "post", data);
1212
},
1313
};

src/components/FormFilter/index.tsx

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,55 +2,48 @@ import { memo, useRef } from "react";
22
import { Button, FormInstance } from "antd";
33
import classNames from "classnames";
44

5-
import FormList from "../FormList";
5+
import FormList, { FormListProps } from "../FormList";
66

7-
export interface FormFilterProps {
7+
export interface FormFilterProps extends Pick<FormListProps, "form" | "onOk" | "onForm" | "onValuesChange" | "initialValues" | "stageValues"> {
8+
className?: string;
9+
filterInfo: FormItem[];
810
reset?: boolean;
9-
compact?: boolean;
1011
loading?: boolean;
11-
className?: string;
12+
compact?: boolean;
1213
searchBtn?: boolean;
13-
14-
filterInfo: FormItem[];
15-
initialValues?: Record<string, any>;
16-
onSubmit?: (value: Record<string, any>) => void;
17-
onForm?: (form: FormInstance) => void;
18-
onValuesChange?: (changedValues: any, values: Record<string, any>) => void;
1914
}
2015

21-
const FormFilter = ({ searchBtn = true, filterInfo, initialValues, reset, loading, compact = false, className, onSubmit, onForm, onValuesChange }: FormFilterProps) => {
16+
const FormFilter = (props: FormFilterProps) => {
17+
const { className, filterInfo, reset, loading, compact = false, searchBtn = true, onForm, ...resetProps } = props;
18+
2219
const formInstance = useRef<FormInstance<any> | null>(null);
2320

2421
const getForm = (form: FormInstance<any>) => {
2522
formInstance.current = form;
26-
onForm && onForm(form);
23+
onForm?.(form);
2724
};
2825

29-
const getBtn = () => {
30-
return (
31-
<div className={compact ? "ml-10" : "absolute bottom-0 right-0"}>
32-
{reset ? <Button htmlType="reset">重置</Button> : null}
26+
const getBtn = () => (
27+
<div className={compact ? "ml-10" : "absolute bottom-0 right-0"}>
28+
{reset ? <Button htmlType="reset">重置</Button> : null}
3329

34-
<Button htmlType="submit" type="primary" loading={loading} className="ml-6">
35-
查询
36-
</Button>
37-
</div>
38-
);
39-
};
30+
<Button className="ml-6" htmlType="submit" type="primary" loading={loading}>
31+
查询
32+
</Button>
33+
</div>
34+
);
4035

4136
return (
42-
<div className={classNames("box-border rounded-md bg-white p-6 dark:border dark:border-dark_border dark:bg-dark_bg", className)}>
37+
<div className={classNames("box-border rounded-md bg-white p-6", className)}>
4338
<FormList
44-
layout="inline"
4539
colon={false}
40+
layout="inline"
4641
submitBtn={false}
4742
className="relative"
4843
itemInfo={filterInfo}
49-
initialValues={initialValues}
5044
searchBtn={searchBtn ? getBtn() : null}
51-
onOk={onSubmit}
5245
onForm={getForm}
53-
onValuesChange={onValuesChange}
46+
{...resetProps}
5447
/>
5548
</div>
5649
);

src/components/FormList/index.tsx

Lines changed: 98 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,130 @@
1-
import { memo, ReactElement, useEffect } from "react";
2-
import { Button, Form, FormInstance } from "antd";
1+
import { memo, ReactElement, useEffect, useMemo } from "react";
2+
import { Button, Form, FormInstance, FormProps } from "antd";
33

44
import { getFormElement } from "../tools";
55

6-
export interface FormFilterProps {
7-
style?: any;
8-
colon?: boolean;
9-
layout?: "horizontal" | "vertical" | "inline";
6+
export interface FormListProps extends Pick<FormProps, "form" | "colon" | "className" | "style" | "layout" | "labelAlign" | "onValuesChange"> {
7+
labelCol?: number;
8+
wrapperCol?: number;
9+
10+
// 搜索
1011
searchBtn?: null | ReactElement;
12+
// 提交
13+
submitBtn?: boolean;
1114
submitNode?: ReactElement;
1215

13-
submitBtn?: boolean;
1416
itemInfo: FormItem[];
15-
className?: string;
16-
labelCol?: number;
17-
wrapperCol?: number;
18-
initialValues?: Record<string, any>;
19-
onOk?: (value: Record<string, any>) => void;
17+
/**
18+
* @description 只在初始化时生效
19+
*/
20+
initialValues?: FormProps["initialValues"];
21+
/**
22+
* @description 该值变化后会触发表单值更新
23+
*/
24+
stageValues?: FormListProps["initialValues"];
25+
onOk?: FormProps["onFinish"];
2026
onForm?: (form: FormInstance) => void;
21-
onValuesChange?: (changedValues: any, values: Record<string, any>) => void;
2227
}
2328

2429
/**
2530
*
2631
* @description extend antd Form
2732
*/
28-
const FormList = ({
29-
style,
30-
colon,
31-
layout,
32-
searchBtn,
33-
submitBtn = true,
34-
submitNode,
35-
itemInfo,
36-
className,
37-
labelCol,
38-
wrapperCol,
39-
initialValues,
40-
41-
onOk,
42-
onForm,
43-
onValuesChange,
44-
}: FormFilterProps) => {
45-
const [form] = Form.useForm();
46-
47-
const onFinish = (value: Record<string, any>) => {
48-
onOk && onOk(value);
49-
};
33+
const FormList = (props: FormListProps) => {
34+
const {
35+
form,
36+
itemInfo,
37+
labelCol,
38+
wrapperCol,
39+
stageValues,
40+
initialValues,
41+
42+
searchBtn,
43+
submitBtn = true,
44+
submitNode,
45+
46+
onOk,
47+
onForm,
48+
...restProps
49+
} = props;
5050

51+
const [insideForm] = Form.useForm();
52+
const realForm = form ? form : insideForm;
53+
54+
// 只在初始化时生效
5155
useEffect(() => {
52-
onForm && onForm(form);
56+
onForm?.(realForm);
5357

5458
if (initialValues) {
55-
form.setFieldsValue(initialValues);
59+
realForm.setFieldsValue(initialValues);
5660
} else {
5761
itemInfo.forEach(e => {
5862
if (e.initialValue !== undefined && e.initialValue !== null) {
59-
form.setFieldValue(e.name, e.initialValue);
63+
realForm.setFieldValue(e.name, e.initialValue);
6064
}
6165
});
6266
}
6367

6468
// eslint-disable-next-line react-hooks/exhaustive-deps
6569
}, []);
6670

71+
// 该值变化后会触发表单值更新
72+
useEffect(() => {
73+
if (stageValues && realForm) {
74+
realForm.setFieldsValue(stageValues);
75+
}
76+
77+
// eslint-disable-next-line react-hooks/exhaustive-deps
78+
}, [JSON.stringify(stageValues)]);
79+
80+
/* ======================= render ========================= */
81+
const submitBtnNode = useMemo(() => {
82+
if (submitBtn) {
83+
if (submitNode) {
84+
return submitNode;
85+
} else {
86+
return (
87+
<Button htmlType="submit" type="primary" block>
88+
保存
89+
</Button>
90+
);
91+
}
92+
} else {
93+
return null;
94+
}
95+
}, [submitBtn, submitNode]);
96+
6797
return (
68-
<div className={className}>
69-
<Form
70-
form={form}
71-
style={style}
72-
labelCol={labelCol ? { span: labelCol } : undefined}
73-
wrapperCol={wrapperCol ? { span: wrapperCol } : undefined}
74-
labelAlign="right"
75-
colon={colon}
76-
layout={layout}
77-
onFinish={onFinish}
78-
onValuesChange={onValuesChange}
79-
>
80-
{itemInfo.map(e =>
81-
e.hide ? null : e.type === "blockNode" ? (
82-
<span key={typeof e.name === "string" ? e.name : e.name.join("_")}>{e.label}</span>
83-
) : (
84-
<Form.Item
85-
key={typeof e.name === "string" ? e.name : e.name.join("_")}
86-
name={e.name}
87-
label={e.label}
88-
extra={e.extra}
89-
rules={[e.rule]}
90-
valuePropName={e.type === "switch" ? "checked" : "value"}
91-
initialValue={e.type === "radio" ? e.options?.[0].value : undefined}
92-
>
93-
{getFormElement(e.type, e)}
94-
</Form.Item>
95-
)
96-
)}
97-
98-
{searchBtn}
99-
100-
{submitBtn ? (
101-
submitNode ? (
102-
submitNode
103-
) : (
104-
<Button htmlType="submit" type="primary" block>
105-
保存
106-
</Button>
107-
)
108-
) : null}
109-
</Form>
110-
</div>
98+
<Form form={realForm} labelCol={labelCol ? { span: labelCol } : undefined} wrapperCol={wrapperCol ? { span: wrapperCol } : undefined} onFinish={onOk} {...restProps}>
99+
{itemInfo.map((e, idx) => {
100+
if (e.hide) {
101+
return null;
102+
}
103+
104+
if (e.type === "blockNode") {
105+
return <span key={typeof e.name === "string" ? e.name || idx : e.name.join("_")}>{e.label}</span>;
106+
}
107+
108+
return (
109+
<Form.Item
110+
label={e.label}
111+
extra={e.extra}
112+
rules={[e.rule]}
113+
hidden={!(e.visible ?? true)}
114+
name={e.name ? e.name : undefined}
115+
valuePropName={e.type === "switch" ? "checked" : "value"}
116+
key={typeof e.name === "string" ? e.name || idx : e.name.join("_")}
117+
initialValue={e.type === "radio" ? e.options?.[0].value : e.type === "switch" ? true : undefined}
118+
>
119+
{getFormElement(e.type, e)}
120+
</Form.Item>
121+
);
122+
})}
123+
124+
{searchBtn}
125+
126+
{submitBtnNode}
127+
</Form>
111128
);
112129
};
113130

0 commit comments

Comments
 (0)