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

使用useContext修改组件全局Set状态不生效的问题排查

问题:通过Context修改Set状态后全局未生效

我希望开发一个支持多组件通过全局上下文(Context)添加、删除Set条目的应用。目前通过useState初始化一个Set,将状态及状态修改函数通过Context Provider传递给子组件,子组件Checkbox根据传入的props添加或删除Set中的条目。但顶层useEffect打印的myList始终是空的(显示(0)),状态修改未产生全局影响,请问哪里出错了?

相关代码

App.js

export const myListContext = createContext(new Set());

function App() {

  const [myList, changeMyList] = useState(() => new Set());

  const Alphabet = {
    A: 'a',
    B: 'b',
  };

  useEffect(() => {
    console.log(myList);
  }, [myList]);

  return (
    <myListContext.Provider value={{ myList, changeMyList }}>
      <div className="my-box">
        <Checkbox myEnum={Alphabet.A} title="Add A to Set"></Checkbox>
        <Checkbox myEnum={Alphabet.B} title="Add B to Set"></Checkbox>
      </div>
    </myListContext.Provider>
  );
}

Checkbox.js

const Checkbox = ({ myEnum, title }) => {

    const { myList, changeMyList } = useContext(myListContext);

    const [index, setIndex] = useState(0);

    function changeIndex() {
        setIndex(index + 1);
        if (index >= 3) {
            setIndex(1);
        }
    }

    function addListItem(item) {
        changeMyList((prev) => new Set(prev).add(item));
    }

    function removeMyListItem(item) {
        changeMyList((prev) => {
            const next = new Set(prev);
            next.delete(item);
            return next;
        });
    }

    function filterItem(item) {
        changeIndex();

        if (index === 0) {
            addListItem(item);
        }

        if (index === 1) {
            removeMyListItem(item);
        }

    }

    return (
        <div className="my-checkbox">
            <div
                className="my-checkbox-inner"
                onClick={() => {
                    filterItem(myEnum);
                }}
            ></div>
            <div className="the-title">{title}</div>
        </div>
    );
}
问题原因及解决方案

核心错误点

  • 状态更新时机错误,依赖闭包旧值:filterItem中先调用changeIndex,再用index判断执行添加/删除,但setIndex是异步操作,此时index还是更新前的旧值,导致添加/删除逻辑永远不会触发,myList自然不会变化。
  • changeIndex逻辑不符合需求:当前逻辑会让index从0→1→2→3→1循环,和你想要的“点击切换添加/删除”逻辑不符,进一步导致状态判断混乱。

修正后的Checkbox.js代码

const Checkbox = ({ myEnum, title }) => {
    const { myList, changeMyList } = useContext(myListContext);
    const [index, setIndex] = useState(0);

    // 简化逻辑:循环切换0(添加)和1(删除)
    function changeIndex() {
        setIndex(prev => prev === 0 ? 1 : 0);
    }

    function addListItem(item) {
        changeMyList((prev) => new Set(prev).add(item));
    }

    function removeMyListItem(item) {
        changeMyList((prev) => {
            const next = new Set(prev);
            next.delete(item);
            return next;
        });
    }

    function filterItem(item) {
        // 先根据当前index执行操作,再更新index
        if (index === 0) {
            addListItem(item);
        } else {
            removeMyListItem(item);
        }
        changeIndex();
    }

    return (
        <div className="my-checkbox">
            <div
                className="my-checkbox-inner"
                onClick={() => filterItem(myEnum)}
            ></div>
            <div className="the-title">{title}</div>
        </div>
    );
}

修正说明

  1. 调整filterItem执行顺序:先基于当前index的状态执行添加/删除,再调用changeIndex更新状态,避免异步更新带来的闭包旧值问题。
  2. 简化changeIndex逻辑:直接在0和1之间切换,精准对应“添加”和“删除”两种操作状态,符合需求。

修改后点击Checkbox组件,顶层App中的useEffect会正确打印更新后的Set,状态修改的全局影响会正常生效。

内容的提问来源于stack exchange,提问作者Kevin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 00:37:08