175 lines
4.7 KiB
Markdown
175 lines
4.7 KiB
Markdown
|
|
---
|
|||
|
|
name: "search-state-persistence"
|
|||
|
|
description: "Search state persistence via tools.router.query. Invoke when implementing search/table pages with SearchForm + Table + pagination that need to preserve query params across refreshes."
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# 搜索状态持久化
|
|||
|
|
|
|||
|
|
通过 `tools.router.query` 实现搜索条件持久化,刷新页面后搜索条件和分页状态保留在 URL 查询参数中。
|
|||
|
|
|
|||
|
|
## 核心 API
|
|||
|
|
|
|||
|
|
```js
|
|||
|
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
|||
|
|
const { router } = tools;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`router.query` 是一个响应式对象,对其赋值会同步更新 URL 查询参数。
|
|||
|
|
|
|||
|
|
## 完整模式
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
import React, { useState, useEffect } from "react";
|
|||
|
|
import { Button, Form, Select, Space, Table, Tag } from "antd";
|
|||
|
|
import PageLayout from "@cqsjjb/jjb-react-admin-component/PageLayout";
|
|||
|
|
import SearchForm from "~/components/SearchForm";
|
|||
|
|
import ControlWrapper from "@cqsjjb/jjb-react-admin-component/ControlWrapper";
|
|||
|
|
import { AntdTableFuncControl } from "@cqsjjb/jjb-common-decorator/antd";
|
|||
|
|
import { tools } from "@cqsjjb/jjb-common-lib";
|
|||
|
|
|
|||
|
|
const { router } = tools;
|
|||
|
|
|
|||
|
|
const MyPage = (props) => {
|
|||
|
|
const [form] = Form.useForm();
|
|||
|
|
const [loading, setLoading] = useState(false);
|
|||
|
|
|
|||
|
|
/** 搜索/刷新数据 */
|
|||
|
|
const handleSearch = () => {
|
|||
|
|
setLoading(true);
|
|||
|
|
// 实际请求...
|
|||
|
|
setTimeout(() => setLoading(false), 500);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/** 重置搜索 */
|
|||
|
|
const handleReset = (values) => {
|
|||
|
|
router.query = {
|
|||
|
|
...router.query,
|
|||
|
|
...values,
|
|||
|
|
current: 1,
|
|||
|
|
size: 10,
|
|||
|
|
};
|
|||
|
|
handleSearch();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/** 初始化:将 URL 中的查询条件回填到表单 */
|
|||
|
|
useEffect(() => {
|
|||
|
|
form.setFieldsValue(router.query);
|
|||
|
|
}, []);
|
|||
|
|
|
|||
|
|
const columns = [
|
|||
|
|
// ...列定义
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
return (
|
|||
|
|
<PageLayout title="页面标题">
|
|||
|
|
<SearchForm
|
|||
|
|
style={{ marginBottom: 24 }}
|
|||
|
|
form={form}
|
|||
|
|
loading={loading}
|
|||
|
|
formLine={[
|
|||
|
|
<Form.Item key="fieldName" name="fieldName">
|
|||
|
|
<ControlWrapper.Input label="字段名" placeholder="请输入" allowClear />
|
|||
|
|
</Form.Item>,
|
|||
|
|
]}
|
|||
|
|
onReset={handleReset}
|
|||
|
|
onFinish={(values) => {
|
|||
|
|
router.query = {
|
|||
|
|
...router.query,
|
|||
|
|
...values,
|
|||
|
|
current: 1,
|
|||
|
|
size: 10,
|
|||
|
|
};
|
|||
|
|
handleSearch();
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
|
|||
|
|
<Table
|
|||
|
|
rowKey="id"
|
|||
|
|
columns={columns}
|
|||
|
|
dataSource={data}
|
|||
|
|
scroll={{ y: props.scrollY }}
|
|||
|
|
loading={loading}
|
|||
|
|
pagination={{
|
|||
|
|
total: total,
|
|||
|
|
showSizeChanger: true,
|
|||
|
|
showQuickJumper: true,
|
|||
|
|
showTotal: (total) => `共 ${total} 条`,
|
|||
|
|
current: router.query.current,
|
|||
|
|
pageSize: router.query.size,
|
|||
|
|
onChange: (page, pageSize) => {
|
|||
|
|
router.query = {
|
|||
|
|
...router.query,
|
|||
|
|
current: page,
|
|||
|
|
size: pageSize,
|
|||
|
|
};
|
|||
|
|
handleSearch();
|
|||
|
|
},
|
|||
|
|
}}
|
|||
|
|
/>
|
|||
|
|
</PageLayout>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export default AntdTableFuncControl(MyPage);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 关键规则
|
|||
|
|
|
|||
|
|
### 1. 初始化回填
|
|||
|
|
在 `useEffect` 中将 `router.query` 的值回填到表单,确保刷新后表单显示与 URL 一致:
|
|||
|
|
```js
|
|||
|
|
useEffect(() => {
|
|||
|
|
form.setFieldsValue(router.query);
|
|||
|
|
}, []);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**注意**:`router.query` 中所有值均为字符串,而 `DatePicker` / `RangePicker` 需要 `dayjs` 对象。当表单包含日期字段时,必须手动转换:
|
|||
|
|
```js
|
|||
|
|
useEffect(() => {
|
|||
|
|
searchForm.setFieldsValue({
|
|||
|
|
...router.query,
|
|||
|
|
dateRange:
|
|||
|
|
router.query.startTime && router.query.endTime
|
|||
|
|
? [dayjs(router.query.startTime), dayjs(router.query.endTime)]
|
|||
|
|
: undefined,
|
|||
|
|
});
|
|||
|
|
}, []);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 搜索/重置写入
|
|||
|
|
搜索提交(`onFinish`) 和重置(`onReset`) 时,将表单值与默认分页合并写入 `router.query`:
|
|||
|
|
```js
|
|||
|
|
router.query = {
|
|||
|
|
...router.query,
|
|||
|
|
...values, // 表单值
|
|||
|
|
current: 1, // 重置到第一页
|
|||
|
|
pageSize: 10, // 默认页大小
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 翻页写入
|
|||
|
|
分页变化时,仅更新 `current` 和 `pageSize`,保留已有搜索条件:
|
|||
|
|
```js
|
|||
|
|
onChange: (page, pageSize) => {
|
|||
|
|
router.query = {
|
|||
|
|
...router.query, // 保留已有搜索条件
|
|||
|
|
current: page,
|
|||
|
|
pageSize,
|
|||
|
|
};
|
|||
|
|
handleSearch();
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. 组件装饰器
|
|||
|
|
页面组件必须用 `AntdTableFuncControl` 包裹以支持表格功能:
|
|||
|
|
```js
|
|||
|
|
export default AntdTableFuncControl(MyPage);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
|
|||
|
|
- `router.query` 是响应式的:赋值会触发 URL 更新,且刷新后值仍然保留
|
|||
|
|
- `router.query` 中所有值均为字符串类型(URL query 的特性),使用 `current` 和 `pageSize` 时注意隐式类型转换
|
|||
|
|
- 默认值 `current: 1, pageSize: 10` 是约定,可根据实际需求修改
|
|||
|
|
- `onReset` 回调的 `values` 参数是重置后的表单值(所有字段清空/恢复默认后的值)
|