You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;

修正说明

  1. 不再嵌套调用setState,直接在更新回调里创建新Set并修改,最后返回新实例
  2. 始终基于prevState创建副本,保证状态更新的不可变性
  3. 渲染时将Set转为数组,避免直接渲染[object Set]

内容的提问来源于stack exchange,提问作者Δημήτρης Τσιδοδήμος

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 16:15:52