You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-hook-form useFieldArray删除异常:误删最后一个元素而非目标元素

React Hook Form useFieldArray 删除元素异常:总是删除最后一个元素

在使用react-hook-form的useFieldArray时遇到问题:点击删除按钮时,并未删除目标元素,反而总是删除最后一个元素。以下是相关代码:

export const isThisAFieldsArrayContext = React.createContext(false)

export default function FieldsArray({
control,
formNamePrefix,
register,
inputsToRender,
addNewDisabled = false,
watchConfig,
...props
}) {
const classes = useStyles()
const { append, remove } = useFieldArray({
    control,
    shouldUnregister: false,
    name: formNamePrefix,
})

const additionalProps = useWatchForAdditionalProps(watchConfig)

function handleRemove(index) {
    remove(index)
}

return (
    <isThisAFieldsArrayContext.Provider value={true}>
        <Grid item xs={12}>
            <List>
                {control.getValues(formNamePrefix)?.map((item, index) => {
                    console.log({ item })
                    return (
                        <ListItem key={index} className={classes.listItem}>
                            <DynamicFormFields
                                {...props}
                                register={register}
                                fieldsKey={`${formNamePrefix}.${index}`}
                                formFields={inputsToRender}
                                control={control}
                                // defaultValue={item.defaultValue}
                            />
                            <DeleteButton
                                variant="contained"
                                onClick={() => handleRemove(index)}
                                aria-label="delete"
                                className={classes.deleteButton}
                            >
                                <DeleteIcon color="secondary" fontSize="small" />
                            </DeleteButton>
                        </ListItem>
                    )
                })}
            </List>
            <Button
                variant="contained"
                onClick={() => append({})}
                aria-label="add"
                color="secondary"
                className={classes.addButton}
                disabled={addNewDisabled || additionalProps.disabled}
            >
                <AddIcon color="primary" />
            </Button>
        </Grid>
    </isThisAFieldsArrayContext.Provider>
)
}

问题原因

  1. 使用数组索引作为React元素key:删除元素后,React的diff算法会误判元素身份。比如删除索引1的元素后,原索引2的元素会变为索引1,React会认为这是原索引1的元素仅内容更新,最终导致删除逻辑与UI不匹配。
  2. 非响应式的列表渲染方式:直接通过control.getValues获取数组渲染,无法同步表单状态的实时变化,导致UI更新滞后。

解决方案

核心修改点

  • 改用useFieldArray返回的fields数组渲染列表(响应式,自动同步状态)
  • 给列表元素设置唯一稳定的key,避免使用索引,建议用元素唯一标识(如自定义id)

修改后的代码示例

// 若使用uuid需先安装:npm install uuid
import { v4 as uuidv4 } from 'uuid';

export const isThisAFieldsArrayContext = React.createContext(false)

export default function FieldsArray({
control,
formNamePrefix,
register,
inputsToRender,
addNewDisabled = false,
watchConfig,
...props
}) {
const classes = useStyles()
// 获取useFieldArray返回的fields数组
const { append, remove, fields } = useFieldArray({
    control,
    shouldUnregister: false,
    name: formNamePrefix,
})

const additionalProps = useWatchForAdditionalProps(watchConfig)

function handleRemove(index) {
    remove(index)
}

return (
    <isThisAFieldsArrayContext.Provider value={true}>
        <Grid item xs={12}>
            <List>
                {/* 用fields数组渲染,以field.id作为key */}
                {fields.map((field, index) => {
                    return (
                        <ListItem key={field.id} className={classes.listItem}>
                            <DynamicFormFields
                                {...props}
                                register={register}
                                fieldsKey={`${formNamePrefix}.${index}`}
                                formFields={inputsToRender}
                                control={control}
                            />
                            <DeleteButton
                                variant="contained"
                                onClick={() => handleRemove(index)}
                                aria-label="delete"
                                className={classes.deleteButton}
                            >
                                <DeleteIcon color="secondary" fontSize="small" />
                            </DeleteButton>
                        </ListItem>
                    )
                })}
            </List>
            <Button
                variant="contained"
                // 添加元素时注入唯一id,保证key稳定
                onClick={() => append({ id: uuidv4() })}
                aria-label="add"
                color="secondary"
                className={classes.addButton}
                disabled={addNewDisabled || additionalProps.disabled}
            >
                <AddIcon color="primary" />
            </Button>
        </Grid>
    </isThisAFieldsArrayContext.Provider>
)
}

补充说明

  • fields数组是useFieldArray提供的响应式数据,会自动同步表单数组的增删改变化,确保UI与状态一致。
  • 若不想引入uuid,也可以用Date.now()生成临时唯一id,或者使用后端返回的唯一标识(如果有)。

内容的提问来源于stack exchange,提问作者Foris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 02:24:11