React中使用useState维护Set时调用has方法报错的原因排查
React中使用useState更新Set集合时
state.has(num)报错的原因 以下组件尝试用useState管理Set类型的状态,但点击按钮后会在state.has(num)处报错。明明state初始化为Set类型,has是Set的内置方法,错误原因如下:
原代码:
import { useState } from "react"; function App() { const [state, setState] = useState(new Set()); console.log(typeof state); function clickHandler(num) { if (!state.has(num)) { setState(prevState => { return setState(new Set(prevState).add(num)) }) } else { setState((prevState) => { return setState(new Set(prevState).delete(num)); }); } } return ( <> <button onClick={() => clickHandler(1)}>1</button> <button onClick={() => clickHandler(2)}>2</button> <button onClick={() => clickHandler(3)}>3</button> { state} </> ); } export default App;
错误原因
嵌套调用setState导致state被覆盖为undefined
在setState的更新回调函数里,你又调用了一次setState。setState本身的返回值是undefined,所以第一次点击后,state会被更新为undefined。等到第二次点击时,state已经是undefined,调用state.has(num)自然会报错——因为undefined没有has方法。Set的
delete方法返回布尔值,而非新Set实例
执行new Set(prevState).delete(num)时,delete方法返回的是布尔值(表示是否成功删除元素),不是修改后的Set。这会导致state被更新为布尔值,后续调用state.has同样会报错。
修正后的代码
import { useState } from "react"; function App() { const [state, setState] = useState(new Set()); function clickHandler(num) { setState(prevState => { // 先创建原Set的副本,避免直接修改原状态 const newSet = new Set(prevState); if (!newSet.has(num)) { newSet.add(num); } else { newSet.delete(num); } // 返回修改后的新Set实例 return newSet; }); } return ( <> <button onClick={() => clickHandler(1)}>1</button> <button onClick={() => clickHandler(2)}>2</button> <button onClick={() => clickHandler(3)}>3</button> {/* 将Set转为数组后渲染,才能显示实际元素 */} {Array.from(state).map(item => ( <span key={item} style={{marginRight: '8px'}}>{item}</span> ))} </> ); } export default App;
修正说明
- 不再嵌套调用setState,直接在更新回调里创建新Set并修改,最后返回新实例
- 始终基于prevState创建副本,保证状态更新的不可变性
- 渲染时将Set转为数组,避免直接渲染
[object Set]
内容的提问来源于stack exchange,提问作者Δημήτρης Τσιδοδήμος
相关产品推荐
相关产品推荐

