使用背景:在一个详情弹窗组件中,引用了搜索组件,每次关闭详情弹窗后再次打开,搜索组件中的值依然显示上次输入或者选择的值。
需求:每次关闭详情弹窗以后再次打开详情弹窗,搜索组件中表单值要重置,也就是搜索组件要重新渲染,状态进行重置。
详情弹窗代码:
import React, { forwardRef, useEffect, useMemo, useState } from 'react';
import { EditOutlined } from '@ant-design/icons';
import './templateDetail.scss';
import { TemplateRecords } from '@/api/interface/msgTemplate';
import { Button, Row, Tag } from 'antd';
import { noGroups, Option } from '@/enums/search';
import SearchBar from '@/components/SearchBar';
import CustomTable from '@/components/Table';
import { cloneDeep } from 'lodash-es';
import { getStatue, ruleEnums, columnGroups } from '@/mocks/template';
import {
delBindMeter,
getBindMeter,
setBindMeter,
getWbFlowMediumClassifyEntity,
unBindAllApis
} from '@/api/modules/alarm';
import { getIndicators } from '@/utils/rulesDict';
interface detailFormProps {
row: TemplateRecords;
[key: string]: any;
}
export interface CustomFormRef {
getForm: () => any;
setForm: (row: TemplateRecords) => void;
clearForm: () => void;
validateForm: () => Promise<void>;
}
const TemplateEditForm = forwardRef<CustomFormRef | undefined, detailFormProps>(
(props: detailFormProps, ref) => {
// 分类获类型数据
const [indicatorsList, setIndicatorsList] = useState<Option[]>([]);
// 已选仪表 水种 体系 评价
const [instrumentList, setInstrumentList] = useState<any[]>([]);
// 新增:表格数据状态管理
const [tableData, setTableData] = useState({
data: [],
total: 0
});
// 新增:加载状态
const [loading, setLoading] = useState(false);
/** 表格参数及表格配置 */
const [requestParam, setRequestParam] = useState<{
ruleId: string;
pageSize: number;
pageNum: number;
[key: string]: any;
}>({
ruleId: props.row?.id,
pageSize: 10,
pageNum: 1
});
// 添加一个 key 状态
const [searchBarKey, setSearchBarKey] = useState(0);
// 清空search表单
const clearForm = () => {
setRequestParam({
ruleId: props.row?.id,
pageSize: 10,
pageNum: 1,
codeOrName: '',
belongModel: '',
type: '',
search: '',
mediumClassifyId: '',
name: ''
});
// 改变key强制重新渲染SearchBar
setSearchBarKey(prev => prev + 1);
};
// 当 props.row变化时清空表单
useEffect(() => {
if (props.row?.id) {
clearForm();
}
}, [props.row?.id]);
// 获取表格数据的方法 --未绑定的仪表
const fetchTableData = async params => {
if (!props.row?.ruleType || !unBindAllApis[props.row?.ruleType]) return;
setLoading(true);
try {
const { data: unBindData } = await unBindAllApis[props.row?.ruleType](params);
if (unBindData) {
const rows = unBindData.records.map((item, index) => ({
no: index + 1,
...item
}));
setTableData({
data: rows || [],
total: unBindData.total ?? 0
});
}
} catch (error) {
console.error('Error fetching table data:', error);
setTableData({ data: [], total: 0 });
} finally {
setLoading(false);
}
};
// 表格操作改变参数
const onParamChange = searchParams => {
... //代码
};
const getBindMeterList = () => {
... //其他代码
};
useEffect(() => {
getBindMeterList();
}, [props.row]);
// 删除
const closeHandle = item => {
delBindMeter(props.row?.id, item.targetId).then(res => {
if (res) {
setInstrumentList(instrumentList.filter(v => v.targetId !== item.targetId));
fetchTableData(requestParam); // 删除后重新获取表格数据
}
});
};
// 选择对象
const selectRow = row => {
...//其他代码
};
// 获取仪表类型
const getIndicatorsList = async () => {
...//其他代码
};
useEffect(() => {
console.log(props.row?.ruleType, 'props.row?.ruleType');
setIndicatorsList([]);
setRequestParam({
...requestParam,
codeOrName: '',
belongModel: '',
type: '',
search: '',
mediumClassifyId: '',
name: ''
});
getIndicatorsList();
const newParams = {
...requestParam,
ruleId: props.row?.id,
type: props.row?.ruleType
};
setRequestParam(newParams);
}, [props.row]);
// 格式化表格数据
const columns = useMemo(
() =>
cloneDeep(columnGroups[props.row?.ruleType] || []).map(item => {
if (item.key === 'status') {
item.render = (text, row) => <div>{getStatue(text)}</div>;
}
if (item.key === 'action') {
item.render = (text, row) => (
<div className="table-handle-btn">
<Button
onClick={() => selectRow(row)}
size="small"
icon={<EditOutlined />}
>
选择
</Button>
</div>
);
}
return item;
}),
[props.row?.ruleType, selectRow]
);
return (
<div className="rules-template-detail">
<Row>
<div>已选{ruleEnums[props.row?.ruleType]}</div>
<div className={'instrument-wrap'}>
{instrumentList.length > 0 &&
instrumentList.map((item, index) => (
<Tag
style={{ marginTop: '10px' }}
key={index}
closeIcon
onClose={e => {
e.preventDefault();
closeHandle(item);
}}
>
{item.targetName}
</Tag>
))}
</div>
</Row>
<Row>
<div className="mb10">待选{ruleEnums[props.row?.ruleType]}</div>
<div style={{ width: '100%' }}>
<SearchBar
key={searchBarKey}
formItemList={noGroups[props.row?.ruleType]?.(indicatorsList) || []}
getSearchParams={onParamChange}
itemCol={10}
btnCol={10}
classSearch={'search-bar-wrap-rules'}
/>
<CustomTable
tableTitle={`${ruleEnums[props.row?.ruleType]}列表`}
currentKey={'pageNum'}
columns={columns}
tableCondition={false}
rowKey="id"
tableData={tableData}
loading={loading}
requestParam={requestParam}
onParamChange={onParamChange}
/>
</div>
</Row>
</div>
);
}
);
TemplateEditForm.displayName = 'TemplateEditForm';
export default TemplateEditForm;
关键代码:
// 添加一个 key 状态
const [searchBarKey, setSearchBarKey] = useState(0);
// 清空search表单
const clearForm = () => {
setRequestParam({
ruleId: props.row?.id,
pageSize: 10,
pageNum: 1,
codeOrName: '',
belongModel: '',
type: '',
search: '',
mediumClassifyId: '',
name: ''
});
// 改变key强制重新渲染SearchBar
setSearchBarKey(prev => prev + 1);
};
// 当 props.row变化时清空表单
useEffect(() => {
if (props.row?.id) {
clearForm();
}
}, [props.row?.id]);
此外,也可以通过 ref 控制 SearchBar 组件重置,首先给 SearchBar 组件添加重置方法:
// SearchBar 组件中添加
export interface SearchBarRef {
resetForm: () => void;
}
const SearchBar = forwardRef<SearchBarRef, any>((props, ref) => {
const [form] = Form.useForm();
// 暴露重置方法
useImperativeHandle(ref, () => ({
resetForm: () => {
form.resetFields();
}
}));
// ... 其他代码
});
然后在详情弹窗中使用:
const TemplateEditForm = forwardRef<CustomFormRef | undefined, detailFormProps>(
(props: detailFormProps, ref) => {
// 添加 SearchBar 的 ref
const searchBarRef = useRef<SearchBarRef>(null);
// 清空表单的方法
const clearForm = () => {
// 清空搜索参数
setRequestParam({
ruleId: props.row?.id,
pageSize: 10,
pageNum: 1,
codeOrName: '',
belongModel: '',
type: '',
search: '',
mediumClassifyId: '',
name: ''
});
// 清空 SearchBar 表单
searchBarRef.current?.resetForm();
// 重新获取数据
fetchTableData({
ruleId: props.row?.id,
pageSize: 10,
pageNum: 1
});
};
// 当 props.row 变化时清空表单
useEffect(() => {
if (props.row?.id) {
clearForm();
}
}, [props.row?.id]);
// 暴露给父组件的方法
useImperativeHandle(ref, () => ({
getForm: () => ({/* ... */}),
setForm: (row: TemplateRecords) => {/* ... */},
clearForm: clearForm,
validateForm: async () => {/* ... */}
}));
return (
<div className="rules-template-detail">
{/* ... 其他代码 */}
<SearchBar
ref={searchBarRef}
formItemList={noGroups[props.row?.ruleType]?.(indicatorsList) || []}
getSearchParams={onParamChange}
itemCol={10}
btnCol={10}
classSearch={'search-bar-wrap-rules'}
/>
{/* ... 其他代码 */}
</div>
);
}
);
二者相比,更推荐第一种通过key强制重新渲染搜索组件,因为:
-
实现简单,代码改动少;
-
通过 React 的 key 机制自然处理重新渲染;
-
不需要修改 SearchBar 组件。

5826

被折叠的 条评论
为什么被折叠?



