使用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> ); }
修正说明
- 调整
filterItem执行顺序:先基于当前index的状态执行添加/删除,再调用changeIndex更新状态,避免异步更新带来的闭包旧值问题。 - 简化
changeIndex逻辑:直接在0和1之间切换,精准对应“添加”和“删除”两种操作状态,符合需求。
修改后点击Checkbox组件,顶层App中的useEffect会正确打印更新后的Set,状态修改的全局影响会正常生效。
内容的提问来源于stack exchange,提问作者Kevin
相关产品推荐
相关产品推荐

