React TypeScript中排序与映射报错问题求助
Next.js 数组索引映射渲染删除元素崩溃问题
背景与问题
我定义了一个包含两个数组的常量,通过与数组索引一致的 state 值 indexOfFrag,根据常量索引映射数组渲染对应数据:
- index 0:对应一组元素列表
- index 1:对应另一组元素列表
点击 index 1 对应的元素时页面崩溃,提示 elements[indexOfFrag] 为 undefined,但 index 0 的元素点击完全正常,报错核心是无法对 undefined 执行 sort 方法。
相关代码
删除元素的处理函数
const handleDeleteElement = ( array: { fid: number; frag: string }[], id: number ) => { const newArray = array.filter((element) => element.fid !== id); setElements([newArray]); };
报错的渲染代码
{showDiv && elements[indexOfFrag].sort(() => Math.random() - 0.5).map((frag, i) => ( <div className={styles.frags} key={i} onClick={() => handleDeleteElement(elements[indexOfFrag], frag.fid)}> <h1>{frag.frag}</h1> </div> ))}
注:showDiv 是布尔类型 state,用于延迟渲染解决服务端与客户端元素不匹配问题(推测是随机 sort 导致)。
尝试过的无效方案
用 useEffect 提前排序并更新 state,但问题依旧:
useEffect(() => { const sortedElements = elements[indexOfFrag].slice().sort(() => Math.random() - 0.5); setElements(prevState => { const newState = [...prevState]; newState[indexOfFrag] = sortedElements; return newState;}); setShowDiv(true) }, []);
问题原因
核心bug在 handleDeleteElement 的 setElements([newArray]) 这行代码:
它直接把 elements 重置成仅包含当前过滤后数组的新数组。比如处理 index 1 的元素时,原本 elements 是包含两个数组的集合,执行这行后变成 [过滤后的index1数组],此时若 indexOfFrag 仍为 1,elements[1] 自然就是 undefined,触发后续 sort 报错。
修复方案
1. 修正删除函数逻辑
只更新对应索引的数组,保留其他索引的数据:
const handleDeleteElement = (id: number) => { setElements(prevElements => { // 复制原数组,避免直接修改state const newElements = [...prevElements]; // 对当前indexOfFrag对应的数组进行过滤 newElements[indexOfFrag] = newElements[indexOfFrag].filter(element => element.fid !== id); return newElements; }); };
2. 优化渲染代码
{showDiv && elements[indexOfFrag]?.sort(() => Math.random() - 0.5).map((frag) => ( <div className={styles.frags} key={frag.fid} onClick={() => handleDeleteElement(frag.fid)}> <h1>{frag.frag}</h1> </div> ))}
优化点:
- 添加可选链
?.,防止elements[indexOfFrag]为 undefined 时直接报错 - 把
key从索引i改成唯一标识frag.fid,避免索引变化导致的渲染异常 - 移除冗余的数组参数传递,直接利用当前 state 的
indexOfFrag,减少 stale state 风险
3. 解决服务端客户端渲染不匹配问题
将随机排序逻辑放在客户端,依赖 indexOfFrag 和 elements 触发更新:
useEffect(() => { if (elements[indexOfFrag]) { const sortedElements = [...elements[indexOfFrag]].sort(() => Math.random() - 0.5); setElements(prev => { const newState = [...prev]; newState[indexOfFrag] = sortedElements; return newState; }); setShowDiv(true); } }, [indexOfFrag, elements]);
内容的提问来源于stack exchange,提问作者Moonlight
相关产品推荐
相关产品推荐

