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

React Map函数未随状态数组更新重渲染,删除功能异常

问题修复:Material UI Select + Formik withFormik 列表删除异常

问题根源

  1. 状态不可变性违反:直接用push()/splice()修改原数组,破坏React状态不可变原则,导致状态更新异常。
  2. 闭包陷阱:删除时依赖当前items变量,而非通过函数式更新获取最新状态,操作的可能是旧状态快照。
  3. index作为key的风险:元素删除后后续元素index会变化,React diff算法错误复用组件,导致删除对应元素错位。

修复步骤

1. 修正添加功能(确保状态不可变)

替换原handleClick,用函数式更新基于旧状态生成新数组,并给每个项添加唯一ID:

const handleClick = ()=>{
  setItems(prevItems => [...prevItems, {
    id: Date.now(), // 生成唯一ID,替代index作为标识
    value: values.name
  }]);
}

2. 修正删除功能(用filter生成新数组)

替换原deleteItem,通过函数式更新获取最新状态,过滤掉目标项:

const deleteItem = (itemId)=>{
  setItems(prevItems => prevItems.filter(item => item.id !== itemId));
}

3. 调整列表渲染的key与props传递

将循环中的index替换为唯一ID作为key和删除标识:

{items.map((item)=>{
  return (
    <List 
      key={item.id} // 用唯一ID作为key
      id={item.id}
      valCountry={item.value}
      onDel={deleteItem}
    />
  );
})}

完整修正后的Form组件代码

import React from 'react'
import { withFormik } from 'formik';
import { FormControl , Select, InputLabel, MenuItem, Fab } from '@mui/material'
import AddIcon from '@mui/icons-material/Add'
import { useState } from 'react';
import List from './List'

const Form = (props) => {
  const[items, setItems]= useState([]);

  const{ values, handleChange, handleSubmit }= props;

  const handleClick = ()=>{
    setItems(prevItems => [...prevItems, {
      id: Date.now(),
      value: values.name
    }]);
  }

  const deleteItem = (itemId)=>{
    setItems(prevItems => prevItems.filter(item => item.id !== itemId));
  }

  return (
    <div className='main'>
      <FormControl sx={{ m: 1, minWidth: 250 }} size="small" onSubmit={handleSubmit}>
        <InputLabel id="country-label">Country</InputLabel>
        <Select
          labelId="Country-label-id"
          id="countries"
          value={values.name}
          label="Country"
          name= "name"
          onChange={handleChange}
        >
          <MenuItem value={9}></MenuItem>
          <MenuItem value={10}>India</MenuItem>
          <MenuItem value={20}>Canada</MenuItem>
          <MenuItem value={30}>Albania</MenuItem>
          <MenuItem value={40}>Zambia</MenuItem>
          <MenuItem value={50}>USA</MenuItem>
          <MenuItem value={60}>Poland</MenuItem>
        </Select>
      </FormControl>
      <Fab size='small' color="primary" aria-label="add" id='button'>
        <AddIcon onClick={handleClick}/>
      </Fab>

      <ul>
        {items.map((item)=>{
          return (
            <List 
              key={item.id}
              id={item.id}
              valCountry={item.value}
              onDel={deleteItem}
            />
          );
        })}
      </ul>
    </div>
  );
}

const MySelectField = withFormik({
  mapPropsToValues: ()=>({name: ''}),
  enableReinitialize: true,

  handleSubmit: (values, { setSubmitting }) => {
    setTimeout(() => {
      console.log(JSON.stringify(values, null, 2));
      setSubmitting(false);
    }, 1000);
  },

})(Form)

export default MySelectField;

补充说明

之前用纯React Hooks正常,是因为当时状态更新写法更规范,没有直接修改原数组。集成Formik后状态更新方式出错,加上index作为key的隐患,最终触发删除异常,本质和Formik无关,是React状态管理的基础问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 10:35:35