0

0

如何解决 React 中删除后无法立即重新添加相同项的问题

霞舞

霞舞

发布时间:2026-01-22 11:16:21

|

224人浏览过

|

来源于php中文网

原创

如何解决 React 中删除后无法立即重新添加相同项的问题

react 中因 `

在你提供的代码中,问题并非出在 useState 更新逻辑或 filter 删除方式上,而是一个经典但容易被忽略的 DOM 行为陷阱

更严重的是,你的当前实现存在多个非 React 推荐的反模式:

  • 使用全局变量 id 而非 React 状态,造成闭包和竞态风险;
  • removeItem 中拼写错误:setMeal(NewList) → 应为 setMeal(newList)(大小写错误);
  • 添加逻辑嵌套双层循环且依赖外部 id,可读性差、性能低(O(n×m));
  • meal.concat(foods[i]) 是函数式写法,但未避免重复添加校验的竞态(因 meal 是旧快照)。

✅ 正确解法:

以下是优化后的完整实现:

import React, { useState } from 'react';
import foods from 'json/foods';

const MealManager = () => {
  const [meal, setMeal] = useState([] as typeof foods);
  const [selectedFoodId, setSelectedFoodId] = useState(''); // ✅ 受控状态

  const removeItem = (id: string) => {
    setMeal(prev => prev.filter(item => item.id !== id));
  };

  const handleAdd = () => {
    if (!selectedFoodId) return;

    const foodToAdd = foods.find(f => f.id === selectedFoodId);
    if (!foodToAdd) return;

    // ✅ 防重复:检查当前 meal 中是否已存在同 id 项(推荐用 id 判断,而非 name)
    if (meal.some(item => item.id === foodToAdd.id)) {
      alert(`"${foodToAdd.name}" is already in the list.`);
      return;
    }

    setMeal(prev => [...prev, foodToAdd]); // ✅ 函数式更新,确保基于最新状态
  };

  return (
    
{/* 渲染已选餐食 */}
{meal.map((item) => (

{item.name}

Protein: {item.protein}

Fats: {item.fats}

Kive
Kive

一站式AI图像生成和管理平台

下载

Carbs: {item.carbs}

))}
{/* 添加区域:受控 select + 明确 Add 按钮 */}
); }; export default MealManager;

? 关键改进说明:

  • 受控组件:select 的 value 绑定到 selectedFoodId 状态,onChange 同步更新——确保状态始终与 UI 一致;
  • Add 按钮职责清晰:不再依赖外部 id 变量,而是直接使用 selectedFoodId 查找并添加,规避了 onChange 不触发的盲区;
  • 去重逻辑健壮:使用 item.id(唯一标识)而非 item.name 判断重复,避免名称冲突风险;
  • 函数式更新:setMeal(prev => [...prev, ...]) 确保在异步渲染中获取最新 meal 快照,防止重复添加漏判;
  • 移除拼写错误与副作用:修复 NewList → newList,消除全局变量 id 带来的不可预测行为。

? 额外建议:

  • 若数据量大,可用 Set 预存已存在 id 提升去重性能;
  • 添加空状态提示(如 “No meals added yet”)提升 UX;
  • 对 foods 数据源做类型守卫(如 TypeScript 接口),避免运行时 undefined 错误。

遵循以上模式,你将彻底解决“删后不能立刻重加”的问题,并写出更可维护、符合 React 最佳实践的代码。

相关专题

更多
全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1049

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

86

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

456

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

11

2026.01.19

go语言闭包相关教程大全
go语言闭包相关教程大全

本专题整合了go语言闭包相关数据,阅读专题下面的文章了解更多相关内容。

136

2025.07.29

undefined是什么
undefined是什么

undefined是代表一个值或变量不存在或未定义的状态。它可以作为默认值来判断一个变量是否已经被赋值,也可以用于设置默认参数值。尽管在不同的编程语言中,undefined可能具有不同的含义和用法,但理解undefined的概念可以帮助我们更好地理解和编写程序。本专题为大家提供undefined相关的各种文章、以及下载和课程。

5088

2023.07.31

Golang 性能分析与pprof调优实战
Golang 性能分析与pprof调优实战

本专题系统讲解 Golang 应用的性能分析与调优方法,重点覆盖 pprof 的使用方式,包括 CPU、内存、阻塞与 goroutine 分析,火焰图解读,常见性能瓶颈定位思路,以及在真实项目中进行针对性优化的实践技巧。通过案例讲解,帮助开发者掌握 用数据驱动的方式持续提升 Go 程序性能与稳定性。

0

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.9万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号