在使用 React Hook Form 和状态管理进行筛选表单开发时,常见的同步问题包括:
# 检查 handleReset 函数是否同时重置表单和查询参数
grep -n "handleReset" src/**/*.tsx
# 检查表单字段是否与查询参数正确映射
grep -n "setSearchParams\|form.reset" src/**/*.tsx
# 检查所有表单字段是否正确定义
grep -n "FormField\|control" src/**/*.tsx | head -10
症状:点击重置按钮后,查询参数被清除但表单字段值保持不变
修复方案:
// 错误示例 - 只重置查询参数
const handleReset = () => {
setSearchParams({
status: undefined,
keyword: undefined,
// ...其他参数
});
};
// 正确示例 - 同时重置表单和查询参数
const handleReset = () => {
// 重置表单字段值
form.reset({
status: undefined,
keyword: undefined,
dateRange: undefined,
// ...所有表单字段
});
// 重置搜索参数
setSearchParams({
status: undefined,
keyword: undefined,
startDate: undefined,
endDate: undefined,
// ...对应查询参数
});
};
症状:筛选表单中的Select组件缺少"全部"选项,用户无法取消筛选
修复方案:
// 错误示例 - 缺少全部选项
<SelectContent>
{Object.values(StatusEnum).map(status => (
<SelectItem key={status} value={status}>
{StatusNameMap[status]}
</SelectItem>
))}
</SelectContent>
// 正确示例 - 添加全部选项(使用特殊值"all"并转换为undefined)
<Select onValueChange={(value) => field.onChange(value === "all" ? undefined : value)} value={field.value || "all"}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="全部状态" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="all">全部状态</SelectItem>
{Object.values(StatusEnum).map(status => (
<SelectItem key={status} value={status}>
{StatusNameMap[status]}
</SelectItem>
))}
</SelectContent>
</Select>
注意事项:
field.value || "all" 来确保选中状态正确显示症状:表单字段名称与查询参数名称不一致
修复方案:
// 确保表单字段名与查询参数名正确映射
const handleSearch = (values: any) => {
setSearchParams({
status: values.status, // 表单字段名 -> 查询参数名
keyword: values.keyword, // 保持一致
startDate: values.dateRange?.[0]?.toISOString(), // 复杂映射
endDate: values.dateRange?.[1]?.toISOString(),
});
};
症状:组件挂载时表单初始值与查询参数不匹配
修复方案:
// 使用 useEffect 同步初始状态
useEffect(() => {
const initialValues = {
status: searchParams.status || undefined,
keyword: searchParams.keyword || undefined,
dateRange: searchParams.startDate && searchParams.endDate
? [new Date(searchParams.startDate), new Date(searchParams.endDate)]
: undefined,
};
form.reset(initialValues);
}, []);
症状:页面使用独立的查询参数而不是通用CRUD的标准filters参数
修复方案:
// 错误示例 - 使用独立参数
const res = await client.$get({
query: {
page: 1,
pageSize: 10,
status: searchParams.status,
problemType: searchParams.problemType,
keyword: searchParams.keyword,
startDate: searchParams.startDate,
endDate: searchParams.endDate,
}
});
// 正确示例 - 使用通用CRUD filters参数
const filters: any = {};
if (searchParams.status) filters.status = searchParams.status;
if (searchParams.problemType) filters.problemType = searchParams.problemType;
if (searchParams.startDate && searchParams.endDate) {
filters.createdAt = {
between: [searchParams.startDate, searchParams.endDate]
};
}
const res = await client.$get({
query: {
page: 1,
pageSize: 10,
keyword: searchParams.keyword, // 独立的关键词参数
filters: Object.keys(filters).length > 0 ? JSON.stringify(filters) : undefined,
}
});
症状:无法通过关联实体的字段进行搜索和筛选(如设备名称、用户名称等)
修复方案:
配置searchFields和relations:
const routes = createCrudRoutes({
entity: YourEntity,
searchFields: ['title', 'description', 'device.zichanInfo.assetName'], // 支持关联字段搜索(格式:relation.field 或 relation.nestedRelation.field)
relations: ['device.zichanInfo'], // 确保关联数据被加载
// ...其他配置
});
使用关联字段筛选:
// 在filters参数中使用关联字段进行精确筛选
const filters = {
'device.zichanInfo.assetName': '服务器001', // 精确匹配
'device.zichanInfo.status': { gte: 1 }, // 范围查询
'device.zichanInfo.department.name': '%IT%' // 模糊匹配
};
const res = await client.$get({
query: {
page: 1,
pageSize: 10,
filters: JSON.stringify(filters)
}
});
别名生成规则:
device.zichanInfo → 别名:device_zichanInfodevice.zichanInfo.department → 别名:device_zichanInfo_departmentdevice_zichanInfo.assetName, device_zichanInfo_department.name支持的筛选操作:
{ "relation.field": "value" }{ "relation.field": "%value%" }{ "relation.field": { "gte": min, "lte": max } }{ "relation.field": [value1, value2, ...] }import React from 'react';
import { useForm } from 'react-hook-form';
import { Form, FormField, FormItem, FormLabel, FormControl } from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Button } from '@/components/ui/button';
import { workOrderClient } from '@/client/api';
export function FilterForm() {
const [searchParams, setSearchParams] = useState({});
const form = useForm();
// 搜索处理 - 使用通用CRUD filters参数
const handleSearch = (values: any) => {
// 构建filters对象
const filters: any = {};
if (values.status) filters.status = values.status;
if (values.problemType) filters.problemType = values.problemType;
if (values.dateRange?.[0] && values.dateRange?.[1]) {
filters.createdAt = {
between: [values.dateRange[0], values.dateRange[1]]
};
}
setSearchParams({
keyword: values.keyword,
filters: Object.keys(filters).length > 0 ? JSON.stringify(filters) : undefined,
});
};
// 重置处理 - 修复后的版本
const handleReset = () => {
// 重置表单字段值
form.reset({
status: undefined,
keyword: undefined,
problemType: undefined,
dateRange: undefined,
});
// 重置搜索参数
setSearchParams({
keyword: undefined,
filters: undefined,
});
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(handleSearch)}>
<FormField
control={form.control}
name="status"
render={({ field }) => (
<FormItem>
<FormLabel>状态</FormLabel>
<Select onValueChange={(value) => field.onChange(value === "all" ? undefined : value)} value={field.value || "all"}>
<FormControl>
<SelectTrigger>
<SelectValue placeholder="选择状态" />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="all">全部状态</SelectItem>
<SelectItem value="active">活跃</SelectItem>
<SelectItem value="inactive">非活跃</SelectItem>
</SelectContent>
</Select>
</FormItem>
)}
/>
<FormField
control={form.control}
name="keyword"
render={({ field }) => (
<FormItem>
<FormLabel>关键字</FormLabel>
<FormControl>
<Input placeholder="输入关键字" {...field} />
</FormControl>
</FormItem>
)}
/>
<div className="flex gap-2">
<Button type="submit">查询</Button>
<Button type="button" variant="outline" onClick={handleReset}>
重置
</Button>
</div>
</form>
</Form>
);
}
#!/bin/bash
# 检查筛选表单常见问题
echo "=== 筛选表单检查 ==="
# 检查 handleReset 函数
echo "1. 检查 handleReset 函数:"
grep -A 10 -B 2 "handleReset" src/**/*.tsx | grep -E "setSearchParams|form.reset"
# 检查表单字段映射
echo "2. 检查表单字段映射:"
grep -A 5 -B 5 "handleSearch" src/**/*.tsx
# 检查初始状态同步
echo "3. 检查初始状态同步:"
grep -A 10 -B 2 "useEffect.*searchParams" src/**/*.tsx
# 检查通用CRUD filters参数使用
echo "4. 检查通用CRUD filters参数使用:"
grep -A 5 -B 5 "filters.*JSON.stringify" src/**/*.tsx
# 检查关联字段搜索配置
echo "5. 检查关联字段搜索配置:"
grep -A 3 -B 3 "searchFields.*\." src/server/api/**/index.ts
echo "=== 检查完成 ==="
使用此指令可以快速识别和修复筛选表单中的常见同步问题,包括通用CRUD filters参数的使用和关联字段搜索功能。
使用此指令可以快速识别和修复筛选表单中的常见同步问题。