React中如何使用useContext将Fullcalendar数据同步存储到localStorage?
问题原因及解决方案
第一个问题(第一条数据存不上)的根源
React的setState是异步更新的,你在调用setState后立刻读取state.externalEvents,拿到的还是更新前的旧值,所以第一次新增时存到localStorage的是空数组,第二次新增时才会存入第一次的内容,看起来就像第一条没保存。
第二个问题(接入Context后功能失效)的常见原因
- App组件缺少return语句:你贴的App组件代码里只写了JSX,没有return包裹,导致Provider根本没有渲染,子组件拿不到Context值。
- 数据结构不匹配:你之前在Todo组件里单独存的是
state.externalEvents数组,但是DataProvider里的todos是{externalEvents: []}的对象结构,初始化时直接把数组赋值给todos,会导致后续读取state.externalEvents为undefined,渲染列表时报错。 - 重复的localStorage写入逻辑:Todo组件里的手动写localStorage代码和Provider里的自动写逻辑冲突,且因为异步问题存的是旧值。
具体修改步骤
步骤1:修正App组件的返回逻辑
给App组件加上return,确保Provider正常包裹所有子组件:
import React from "react"; import {DataProvider} from './components/calendar/DataProvider' // 其他导入... function App() { return ( <DataProvider> {/* 你的其他布局代码 */} <Switch> {/* 其他路由 */} <Route path="/calendar" component={Calendar} /> </Switch> </DataProvider> ) } export default App;
步骤2:优化DataProvider的初始化逻辑,兼容旧数据
修改DataProvider里的初始化useEffect,处理之前存的数组格式旧数据,避免结构不匹配:
import React,{useState,useEffect,createContext} from 'react' export const DataContext = createContext(); export const DataProvider = (props) => { const [todos, setTodos] = useState({ externalEvents: [], }); useEffect(() => { const todoStore = JSON.parse(localStorage.getItem('todoStore')) if(todoStore) { // 兼容旧版数组格式的存储数据 if(Array.isArray(todoStore)) { setTodos({ externalEvents: todoStore }) } else { setTodos(todoStore) } } },[]) useEffect(() => { localStorage.setItem('todoStore', JSON.stringify(todos)); },[todos]) return ( <DataContext.Provider value={[todos,setTodos]}> {props.children} </DataContext.Provider> ) }
步骤3:替换Calendar组件的本地状态为Context全局状态
在Calendar组件中导入DataContext,替换原来的本地useState:
import { useContext } from 'react' import { DataContext } from './DataProvider' // 其他导入... export default function Calendar() { // 替换原来的const [state, setState] = useState({externalEvents: []}) const [state, setState] = useContext(DataContext) // 剩下的原有代码不变,继续把state和setState传给Todo组件即可 }
步骤4:删除Todo组件里冗余的localStorage代码
删掉Todo组件addTodo函数里的手动存localStorage的那行,现在Provider会自动处理持久化,避免异步导致的存旧值问题:
const addTodo = (e) => { e.preventDefault(); if (title === "" || color === "") { alert("please type what to do or choose a color"); } else { setState({ externalEvents: [ ...state.externalEvents, { title: title, color: color, custom: custom, id: uuidv4(), }, ], }); // 删掉下面这行!!! // localStorage.setItem("todoStore", JSON.stringify(state.externalEvents)); setTitle(""); setCustom(""); } };
验证效果
修改完成后:
- 新增第一条数据就会自动同步到localStorage,不会再出现丢失的情况
- 刷新页面后,Provider会自动从localStorage读取数据,事件列表不会丢失
- 所有子组件都可以通过useContext拿到最新的事件列表,实现全局状态共享
内容的提问来源于stack exchange,提问作者geo
相关产品推荐
相关产品推荐

