React删除列表对象后UI未正确重渲染Input组件如何解决
问题原因
你遇到的删除后UI不更新问题,是两个典型的React列表渲染错误叠加导致的,和初始空对象的设置没有直接关系:
- 用数组索引作为列表
key:React依赖key值判断组件是否需要更新、复用还是销毁。当你删除列表中间项时,后续项的索引会顺位前移,React会错误判定组件没有变化,直接复用之前的Input组件实例,连组件内部的value、submitted本地状态都不会重置,最终出现数据已更新但UI显示错位、看起来没删除的问题。 - 列表项结构不统一+过滤逻辑漏洞:初始
list值为[{}],这个空对象没有id字段,执行filter(item => item.id !== id)时,空对象的id是undefined,永远不等于传入的数字id,导致这个初始项永远不会被过滤掉,列表长度和实际渲染的组件数不匹配。
修复方案
按照以下三点调整即可,同时满足「列表至少保留1个输入项」的业务要求:
- 给每个列表项分配全局唯一、从创建到删除保持不变的id作为key,绝对不要用数组索引当key
- 统一所有列表项的数据结构,初始项也带上合法id,不要留没有id的空对象
- 调整提交、删除逻辑:提交时先更新当前项的输入值,再追加新的空输入项;删除时判断列表长度,长度为1时阻止删除,保证至少留1项。
修复后代码
父组件 App.jsx
import "./styles.css"; import { useState, useEffect } from "react"; import Input from "./Input"; // 生成唯一id的工具函数,也可以替换为现代浏览器原生支持的 crypto.randomUUID() let idCounter = 0; const getUniqueId = () => idCounter++; export default function App() { // 初始项直接带上唯一id,结构和后续新增项统一 const [list, setList] = useState([{ id: getUniqueId() }]); useEffect(() => { console.log("list", list); }, [list]); return ( <div className="App"> <h1>Hello CodeSandbox</h1> <h2>Start editing to see some magic happen!</h2> {list.map((item) => ( // 用项自身的稳定id作为key,不要用数组索引i <div key={item.id}> <Input id={item.id} setList={setList} /> </div> ))} </div> ); }
子组件 Input.jsx
import { useState } from "react"; // 实际使用时把getUniqueId抽到公共工具文件引入即可 let idCounter = 0; const getUniqueId = () => idCounter++; const Input = ({ setList, id }) => { const [value, setValue] = useState(""); const [submitted, setSubmitted] = useState(false); const handleChange = (event) => { const result = event.target.value.replace(/\D/g, ""); setValue(result); }; const handleSubmit = () => { setList((list) => [ // 先更新当前提交项的total值 ...list.map(item => item.id === id ? {...item, total: value} : item), // 追加新的空输入项 { id: getUniqueId() } ]); setSubmitted(true); }; const handleDelete = () => { setList((list) => { // 列表只剩1项时阻止删除,满足至少1项的要求 if (list.length <= 1) return list; return list.filter((item) => item.id !== id); }); }; return ( <div> <input value={new Intl.NumberFormat("ko-KR", { style: "currency", currency: "KRW" }).format(Number(value))} onChange={handleChange} type="text" /> {submitted ? ( <button disabled={value.length === 0} onClick={handleDelete}> Delete </button> ) : ( <button disabled={value.length === 0} onClick={handleSubmit}> Submit! </button> )} </div> ); }; export default Input;
修复后React可以通过稳定的key准确识别每个Input组件的增删,删除对应项时会直接销毁对应的组件实例,不会出现状态复用错位的问题,UI会和list状态完全同步。
内容的提问来源于stack exchange,提问作者dev_el
相关产品推荐
相关产品推荐

