React Hook Form useFieldArray筛选异常:搜索'test'显示错误行
问题:React Hook Form结合useFieldArray筛选列表时显示异常
使用React Hook Form结合useFieldArray创建列表,通过搜索框实现列表筛选时功能异常:搜索“test”时,本该显示最后两行含“test”的条目,却显示了前两行。
代码示例
import React from 'react'; import { useForm, useFieldArray, Controller, useWatch } from 'react-hook-form'; import ReactDOM from 'react-dom'; let renderCount = 0; export function App() { const { register, control, handleSubmit, reset, watch } = useForm({ defaultValues: { test: [ { firstName: 'Bill 1', lastName: 'Luo' }, { firstName: 'hello2', lastName: 'Luo' }, { firstName: 'test 3', lastName: 'Luo' }, { firstName: 'test 4', lastName: 'Luo' }, ], }, }); const { fields, append, prepend, remove, swap, move, insert, replace } = useFieldArray({ control, name: 'test', }); const onSubmit = data => console.log('data', data); const [searchQuery, setSearchQuery] = React.useState(''); const handleSearchChange = event => { setSearchQuery(event.target.value); }; const filteredRows = fields.filter(row => row.firstName.toLowerCase().includes(searchQuery.toLowerCase()) ); console.log(JSON.stringify(filteredRows)); return ( <> <input onChange={handleSearchChange} value={searchQuery} /> <form onSubmit={handleSubmit(onSubmit)}> <ul> {filteredRows.map((item, index) => { return ( <li key={item.id}> <input {...register(`test.${index}.firstName`, { required: true })} /> <Controller render={({ field }) => <input {...field} />} name={`test.${index}.lastName`} control={control} /> </li> ); })} </ul> </form> </> ); } // Log to console console.log('Hello console');
问题原因
核心错误在于使用筛选后数组的index作为表单字段的路径索引:
- 当你对
fields数组筛选得到filteredRows后,map循环的index是筛选后数组的索引(比如搜索“test”后,filteredRows有2条数据,索引为0和1) - 但你绑定的字段路径是
test.${index}.firstName,这会指向原始fields数组的第0、1项(即“Bill 1”和“hello2”对应的字段),而非筛选出来的“test 3”、“test 4”项 - 最终表现为:你渲染了筛选后的条目结构,但实际绑定的是原始数组前两项的表单值,所以看起来显示的是前两行。
解决方法
通过每个条目的唯一id找到它在原始fields数组中的索引,用这个原始索引来绑定表单字段路径:
{filteredRows.map((item) => { // 找到当前条目在原始fields数组中的索引 const originalIndex = fields.findIndex(row => row.id === item.id); return ( <li key={item.id}> <input {...register(`test.${originalIndex}.firstName`, { required: true })} /> <Controller render={({ field }) => <input {...field} />} name={`test.${originalIndex}.lastName`} control={control} /> </li> ); })}
这样就能确保筛选后的条目正确绑定到对应的数据字段,显示内容与筛选结果一致。
内容的提问来源于stack exchange,提问作者user944513
相关产品推荐
相关产品推荐

