React对象数组过滤:为何第一种实现失效?求最优方案
数组过滤失效原因及最优实现方案
一、两种实现的差异原因
第一种实现失效的核心问题
- 异步状态更新延迟:
setInputValue是React异步状态更新方法,执行filter时,inputValue还是更新前的旧值,导致过滤逻辑用错了输入内容。 - 原始数据被覆盖:直接用
setData(filteredNotes)把过滤后的子集替换了原始完整数据。第一次过滤后,data就变成了原始数据的一部分,后续再输入过滤条件时,只能基于这个子集继续筛选,最终导致原始数据丢失,看起来像是“误删”。
第二种实现正常的原因
始终保留原始完整数据在data状态里,没有修改它。每次组件渲染时,都基于最新的inputValue对原始数据做实时过滤,既保证了过滤逻辑用的是最新输入值,又不会丢失原始数据。
二、最优实现方式
根据数据规模和业务需求,有几种不同的最优方案:
1. 小数据量场景(直接用渲染时过滤)
就是第二种实现的思路,代码简洁易维护,不需要额外优化:
const [data, setData] = useState(JSON.parse(localStorage.getItem("notes") ?? "[]")); const [inputValue, setInputValue] = useState(""); return ( <> <input onChange={(e) => setInputValue(e.target.value)} value={inputValue}/> {data .filter((val) => val.text.toLowerCase().includes(inputValue.toLowerCase())) .map((note) => ( <Note key={note.id} note={note} onExpandCheck={setIsExpandedCheck} onNoteDelete={handleNoteDelete} onNoteSave={handleNoteSave} /> ))} </> )
(注:这里把inputValue也转成小写,避免大小写敏感的问题)
2. 大数据量场景(用useMemo缓存过滤结果)
如果数据量很大,每次渲染都执行filter会有性能损耗,可以用useMemo缓存过滤后的结果,只有当data或inputValue变化时才重新计算:
const [data, setData] = useState(JSON.parse(localStorage.getItem("notes") ?? "[]")); const [inputValue, setInputValue] = useState(""); // 缓存过滤结果 const filteredData = useMemo(() => { return data.filter(val => val.text.toLowerCase().includes(inputValue.toLowerCase())) }, [data, inputValue]) return ( <> <input onChange={(e) => setInputValue(e.target.value)} value={inputValue}/> {filteredData.map((note) => ( <Note key={note.id} note={note} onExpandCheck={setIsExpandedCheck} onNoteDelete={handleNoteDelete} onNoteSave={handleNoteSave} /> ))} </> )
3. 需要保留过滤后状态的场景
如果业务需要同时保留原始数据和过滤后的状态(比如需要对过滤结果做修改),可以把原始数据存在单独的状态或useRef里:
// 保存原始完整数据 const [rawData, setRawData] = useState(JSON.parse(localStorage.getItem("notes") ?? "[]")); const [inputValue, setInputValue] = useState(""); // 可选:如果需要单独维护过滤后的状态 const [filteredData, setFilteredData] = useState(rawData); // 监听输入变化,更新过滤结果 useEffect(() => { setFilteredData(rawData.filter(val => val.text.toLowerCase().includes(inputValue.toLowerCase()))) }, [rawData, inputValue]) return ( <> <input onChange={(e) => setInputValue(e.target.value)} value={inputValue}/> {filteredData.map((note) => ( <Note key={note.id} note={note} onExpandCheck={setIsExpandedCheck} onNoteDelete={handleNoteDelete} onNoteSave={handleNoteSave} /> ))} </> )
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

