Skip to content

Commit 9647e73

Browse files
haiminovoLuckyFBB
authored andcommitted
add parameter 'clearData' to useList mutate function (#418)
* optimized useList clear data before mutate request * add unit testing and desc * add demo to mutate options
1 parent 669c06f commit 9647e73

File tree

4 files changed

+162
-0
lines changed

4 files changed

+162
-0
lines changed

src/useList/__tests__/useList.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,25 @@ describe('Test useList hook', () => {
133133
await awaitTimers();
134134
expect(result.current.loading).toBe(false);
135135
});
136+
137+
it('Should support clear data before mutate', async () => {
138+
const fetcher = jest.fn().mockResolvedValue({
139+
total: 1,
140+
data: [{ uuid: 1 }],
141+
error: new Error('testError'),
142+
});
143+
const { result } = renderHook(() =>
144+
useList(fetcher, { current: 1, pageSize: 20, search: '' })
145+
);
146+
expect(fetcher).toBeCalledTimes(1);
147+
await waitFor(() => {
148+
expect(result.current.data.length).toBe(1);
149+
});
150+
act(() => {
151+
result.current.mutate({ search: 'test' }, { clearData: true });
152+
});
153+
expect(result.current.data).toStrictEqual([]);
154+
expect(result.current.params.total).toBe(0);
155+
expect(result.current.error).toBe(undefined);
156+
});
136157
});
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import React, { useState } from 'react';
2+
import { Button, Form, Input, Result, Select, Switch, Table } from 'antd';
3+
import { useList } from 'dt-react-component';
4+
import type { Fetcher } from 'dt-react-component/useList';
5+
6+
import getMockData, { type MockData } from './data';
7+
8+
const fetcher: Fetcher<MockData, { current: number; pageSize: number; search?: string }> = (
9+
params
10+
) => {
11+
return new Promise<{
12+
data: MockData[];
13+
total: number;
14+
}>((resolve) => {
15+
setTimeout(() => {
16+
resolve(getMockData(params));
17+
}, 150);
18+
});
19+
};
20+
21+
export default () => {
22+
const { error, params, loading, data, mutate } = useList(fetcher, { current: 1, pageSize: 20 });
23+
const [form] = Form.useForm();
24+
25+
if (error) return <Result status={500} />;
26+
27+
const handleSearch = async () => {
28+
const values = await form.validateFields();
29+
mutate({ ...values }, { revalidate, clearData });
30+
};
31+
32+
const handleReset = async () => {
33+
form.resetFields();
34+
const values = await form.validateFields();
35+
// 当传入值有 undefined 的时候,采用 functional 的写法。
36+
// 因为底层使用的 lodash 的 merge,采用赋值写法不会对 undefined 做合并
37+
mutate((pre) => ({ ...pre, ...values }), { revalidate, clearData });
38+
};
39+
const [revalidate, setRevalidate] = useState(true);
40+
const [clearData, setClearData] = useState(true);
41+
const onChangeRevalidate = () => {
42+
setRevalidate(!revalidate);
43+
};
44+
const onChangeClearData = () => {
45+
setClearData(!clearData);
46+
};
47+
48+
return (
49+
<>
50+
<Form layout="inline" form={form}>
51+
<Form.Item name="search">
52+
<Input.Search style={{ marginBottom: 12, width: 228 }} />
53+
</Form.Item>
54+
<Form.Item name="filters">
55+
<Select style={{ width: 228 }} mode="multiple">
56+
<Select.Option key="female" value="female">
57+
female
58+
</Select.Option>
59+
<Select.Option key="male" value="male">
60+
male
61+
</Select.Option>
62+
</Select>
63+
</Form.Item>
64+
<Button type="ghost" style={{ marginRight: 16 }} onClick={handleReset}>
65+
重置
66+
</Button>
67+
<Button type="primary" style={{ marginRight: 32 }} onClick={handleSearch}>
68+
查询
69+
</Button>
70+
<Form.Item name="options">
71+
<span style={{ marginRight: 4 }}>revalidate</span>
72+
<Switch
73+
style={{ marginRight: 16 }}
74+
defaultChecked
75+
onChange={onChangeRevalidate}
76+
/>
77+
<span style={{ marginRight: 4 }}>clearData</span>
78+
<Switch defaultChecked onChange={onChangeClearData} />
79+
</Form.Item>
80+
</Form>
81+
<Table
82+
loading={loading}
83+
columns={[
84+
{
85+
key: 'name',
86+
title: 'name',
87+
dataIndex: 'name',
88+
},
89+
{
90+
key: 'address',
91+
title: 'address',
92+
dataIndex: 'address',
93+
},
94+
{
95+
key: 'company',
96+
title: 'company',
97+
dataIndex: 'company',
98+
},
99+
{
100+
key: 'gender',
101+
title: 'gender',
102+
dataIndex: 'gender',
103+
},
104+
{
105+
key: 'weight',
106+
title: 'weight',
107+
dataIndex: 'weight',
108+
},
109+
]}
110+
onChange={(pagination) =>
111+
mutate(
112+
{ current: pagination.current, pageSize: pagination.pageSize },
113+
{ revalidate, clearData }
114+
)
115+
}
116+
size="small"
117+
scroll={{ y: 200 }}
118+
dataSource={data}
119+
pagination={{
120+
current: params.current,
121+
pageSize: params.pageSize,
122+
total: params.total,
123+
}}
124+
rowKey="uuid"
125+
bordered
126+
/>
127+
</>
128+
);
129+
};

src/useList/index.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ toc: content
1616
<code src="./demos/sort.tsx" title="筛选和过滤"></code>
1717
<code src="./demos/options.tsx" title="相关配置" description="设置 immediate 值防止初始化的时候进行请求"></code>
1818
<code src="./demos/mutate.tsx" title="相关配置" description="用 undefined 覆盖 prevPrams 时,需采用 functional 的写法 "></code>
19+
<code src="./demos/mutateOptions" title="mutate相关配置" description="revalidate 修改后请求数据,clearData 请求前清除数据"></code>
1920

2021
## API
2122

@@ -49,3 +50,4 @@ toc: content
4950
| 参数 | 说明 | 类型 | 默认值 |
5051
| ---------- | ---------------------- | --------- | ------ |
5152
| revalidate | 修改后是否重新请求数据 | `boolean` | `true` |
53+
| clearData | 请求数据前是否清除数据 | `boolean` | `true` |

src/useList/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export interface IMutateOptions {
88
* 是否数据重新获取
99
*/
1010
revalidate?: boolean;
11+
/**
12+
* 在mutate发起请求前是否清空data(包括data total error)
13+
*/
14+
clearData?: boolean;
1115
}
1216

1317
export interface IUseListOptions {
@@ -49,13 +53,19 @@ export default function useList<T extends Record<string, any>, P extends Record<
4953
const mutate = (next: Partial<P> | ((prev: P) => P) = params, options: IMutateOptions = {}) => {
5054
const defaultOptions: IMutateOptions = {
5155
revalidate: true,
56+
clearData: true,
5257
};
5358
const nextOptions = merge(defaultOptions, options);
5459

5560
const tmp = typeof next === 'function' ? next(params) : { ...merge({}, params, next) };
5661
setParams(tmp);
5762

5863
if (nextOptions.revalidate) {
64+
if (nextOptions.clearData) {
65+
setData([]);
66+
setTotal(0);
67+
setError(undefined);
68+
}
5969
performFetch(tmp);
6070
}
6171
};

0 commit comments

Comments
 (0)