9.记录
leezozz 12/8/2023 react
# 1. 场景:
接口获取表格数据(包含表头、表体数据)之后,手动处理表头数据,表头添加点击事件,点击的同时把当前的分页数据传递进去
const getDataPreviewTable = async (arg: {
current: number;
pageSize: number;
sideId: string; // 选中侧边栏id
}): Promise<{
total: number;
body: bodyListType[];
columns: ColumnItem[];
list: [];
}> => {
if (!params.testId) {
return {
total: 0,
columns: [],
body: [],
list: [],
};
}
const { error, data } = await testApi({
id: params.testId,
page: arg.current,
limit: arg.pageSize,
});
// 处理表体的数据
const newBody = data?.body?.map((item: ItemBody, index: number) => ({
...item,
key: index,
}));
// 注意:表头数据处理不要写这里。如果写这里,点击表头,(此时的分页是接口返回之前的,也就是旧的分页数据)。会有闭包问题,不是实时的分页数据。
return {
total: data?.total || 0,
columns: data?.table_schema || [],
body: newBody || [],
list: [],
};
};
// 这里使用ahooks的usePagination钩子
// refreshDeps:依赖的条件。当依赖条件改变时,会重置 current 到第一页,并重新发起请求
const { data, loading, pagination } = usePagination(getDataPreviewTable, {
defaultPageSize: 20,
refreshDeps: [params.testId, renewTableData],
});
// 拆分处理
const handleSplit = (item: ColumnItem) => {
const onFinished = async (value: SplitFieldType) => {
// 重新获取外层数据列表接口
if (!params.testId) {
return;
}
const { error, data } = await SharedApi.getFieldDelimiter({
project_id: params.testId,
split_info: {
split_field: item,
split_method: value.xxx,
},
});
if (error) {
return;
}
setRenewTableData(!renewTableData);
destroy();
};
const { destroy } = modal.info({
className: styles["custom-member-management-modal"],
title: (
<div className="flex justify-between px-6 border-0 border-b-[1px] border-slate-200 border-solid">
<p>拆分字段</p>
<CloseOutlined onClick={() => destroy()} />
</div>
),
footer: null,
width: 800,
content: (
<SplitField
projectId={params.testId}
page={pagination.current}
limit={pagination.pageSize}
onFinish={onFinished}
onClosed={() => destroy()}
/>
),
icon: <></>,
});
};
// 注意:表头处理。【表头处理尽量不要写在接口返回的函数里,可能会有闭包问题】
// 这里处理表头的render,添加icon
const columns =
data?.columns?.map(item => {
const getItems = (item: ColumnItem) => {
return [
{
key: "1",
label: (
<a className="px-[30px]" onClick={() => handleSplit(item)}>
拆分
</a>
),
},
{
key: "2",
label: (
<a className="px-[30px]" onClick={() => handleMerge(item)}>
合并
</a>
),
},
];
};
return {
...item,
title: () => {
return (
<>
<div className="flex justify-between">
<span>{item.new_name}</span>
<Dropdown
menu={{
items: getItems(item),
}}
placement="bottom"
>
<MoreOutlined className="cursor-pointer" />
</Dropdown>
</div>
</>
);
},
dataIndex: item.base_name,
key: item.base_name,
};
}) || [];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# 2. 场景:
- 一个tsx文件中,尽量不要写多个组件,每个组件都抽离成单独的文件,避免重复渲染,多次更新造成问题!!!
- 组件中尽量少声明useState,可以使用已声明useState的衍生出来的变量
# 3. antd组件库中的form
form.Item会默认传递value、onChange
<Form.Item<FieldType>
label="Username"
name="username"
rules={[{ required: true, message: 'Please input your username!' }]}
>
{/* 默认向包裹的组件(自定义<CustomInput />组件)传递了value、onChange */}
<CustomInput />
</Form.Item>
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 4. setId保持
修改、编辑之后重新获取列表,保持当前选中侧边id
setCurrentSelectKey(currentSelectKey => currentSelectKey || data.rules[0]?.id)
1
# 5. 子组件点击按钮触发父组件事件
- 通过props和回调函数的方式实现(场景:子组件表单提交后,触发父组件列表更新)
// 父组件
import { useState, useEffect } from 'react';
function Parent() {
const [list, setList] = useState([]);
useEffect(() => {
// 初始化加载list
}, [])
// 当子组件表单提交后重新获取列表
const onChildFormSubmit = () => {
fetchList().then(newList => {
setList(newList);
})
}
return (
<Child onFormSubmit={onChildFormSubmit} />
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 子组件
function Child({onFormSubmit}) {
const onSubmit = () => {
// 处理表单校验
// 提交表单数据给接口
onFormSubmit(); // 提交后调用父组件方法
}
return (
<Form>
<button onClick={onSubmit}>提交</button>
</Form>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- 子组件影响父组件的状态变化
// 创建Context
const CounterContext = React.createContext();
1
2
2
// 父组件提供Context值
export const Parent = () => {
const [count, setCount] = useState(0);
return (
<CounterContext.Provider
value={{count, setCount}}
>
<Child />
</CounterContext.Provider>
)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
// 子组件消费Context更新父组件状态
export const Child = () => {
const { setCount } = useContext(CounterContext);
const onSubmit = () => {
// submit logic
setCount(count + 1);
}
return <div>...</div>;
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
- 可以使用EventBus。