
react 列表操作中,因 `
在 React 中,
✅ 正确做法:使用受控组件 + 清空 select 值
将
import foods from 'json/foods';
const [meal, setMeal] = useState([]);
const [selectedFoodName, setSelectedFoodName] = useState(''); // ✅ 受控状态
const handleAdd = () => {
if (!selectedFoodName) return;
const foodToAdd = foods.find(food => food.name === selectedFoodName);
if (!foodToAdd) return;
// 防重:检查是否已存在同名项(推荐用 id 判断更可靠)
if (meal.some(item => item.id === foodToAdd.id)) {
alert(`"${foodToAdd.name}" 已在列表中`);
return;
}
setMeal(prev => [...prev, foodToAdd]);
setSelectedFoodName(''); // ✅ 添加后立即清空 select
};
const handleRemove = (id) => {
setMeal(prev => prev.filter(item => item.id !== id));
};
对应 JSX 更新如下:
<div>
{/* 渲染列表 */}
{meal.map((item) => (
<div key="{item.id}">
<h2>{item.name}</h2>
<div>
<p>Protein: {item.protein}</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill11164" title="jm-jsjkxyjs02-zlm-405"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20e352aa140.jpg" alt="jm-jsjkxyjs02-zlm-405" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill11164" title="jm-jsjkxyjs02-zlm-405" class="overflowclass">jm-jsjkxyjs02-zlm-405</a>
<p class="overflowclass">使用约定式提交(Conventional Commits)生成标准化的 Git 提交信息。适用于以下场景:
(1) 暂存更改时需要提交信息;
(2) 审查 diff 时希望获得结构化摘要;
(3) 编写 PR 描述或变更日志(changelog)条目;
(4) 用户明确要求“为本次更改编写提交信息”。
该功能会分析已暂存/未暂存的 diff,并生成按类型(type)划分范围的提交信息。</p>
</div>
<a rel="nofollow" href="/xiazai/skill11164" title="jm-jsjkxyjs02-zlm-405" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p>Fats: {item.fats}</p>
<p>Carbs: {item.carbs}</p>
<ioiosremovecircle onclick="{()"> handleRemove(item.id)} />
</ioiosremovecircle>
</div>
</div>
))}
</div>
<div>
{/* 受控 select */}
<select value="{selectedFoodName}" onchange="{(e)"> setSelectedFoodName(e.target.value)}
>
<option value="">-- 选择食物 --</option>
{foods.map((food) => (
<option key="{food.id}" value="{food.name}">
{food.name}
</option>
))}
</select><button onclick="{handleAdd}">Add</button>
</div>
⚠️ 注意事项与最佳实践
- 优先用 id 而非 name 去重:食物名称可能重复(如不同品牌的“Oatmeal”),而 id 是唯一标识,更健壮;
- 避免全局变量 id:原代码中 let id; 是模块级变量,易引发闭包和竞态问题,必须用 useState 管理;
- 不要直接修改 state 数组:meal.concat(...) 虽可用,但推荐使用函数式更新 setMeal(prev => [...prev, newItem]),确保基于最新状态;
- key 必须稳定唯一:确保 foods 和 meal 数据中的 id 字段真实唯一且不可变,否则 React 渲染会出现异常。
通过受控组件 + 显式重置,你不仅能解决“删后无法重加”的问题,还能让数据流更清晰、可预测,符合 React 的单向数据流设计哲学。










