react-grid-layout的onLayoutChange刷新时重置localStorage布局数据如何解决
问题根因
- 仅存储了布局配置
layouts到localStorage,未存储动态添加的items、charts列表以及计数器newCounter、chartCounter的值,页面刷新后动态添加的元素全部丢失,原有布局和当前元素无法匹配,react-grid-layout会自动生成默认布局覆盖原有存储值。 - 组件挂载阶段就会触发
onLayoutChange回调,此时直接执行存储逻辑会把初始默认布局覆盖localStorage中存储的自定义布局。 - localStorage读写本身是同步API,不存在异步读取未完成的问题,所有异常都来自状态匹配错误和初始化触发的误写入。
修复方案
- 第一步:抽离统一的全状态保存方法,将布局相关的所有动态状态都存入localStorage
saveAllToLS() { if (global.localStorage) { global.localStorage.setItem( "rgl-8", JSON.stringify({ layouts: this.state.layouts, items: this.state.items, charts: this.state.charts, newCounter: this.state.newCounter, chartCounter: this.state.chartCounter }) ); } }
- 第二步:修改初始化逻辑,读取localStorage时恢复所有状态,没有存储值时才用默认值,同时新增挂载标记避免初始化误写入
constructor(props) { super(props); // 读取存储的全量状态 const savedState = getFromLS() || {}; this.state = { layouts: savedState.layouts || {}, inputWidthVal: "", inputHeightVal:"", // 优先读取存储的元素列表,没有才用默认值 items: savedState.items || [0, 1, 2, 3, 4].map(function (i) { return { id: uuidV4(), i: i.toString(), x: i * 2, y: 0, w: 1, h: 1 }; }), charts: savedState.charts || [0].map(function (i) { return { id: uuidV4(), i: i.toString(), x: i, y: 0, w: 4, h: 3 }; }), // 优先读取存储的计数器,避免新增元素的i属性重复 newCounter: savedState.newCounter || 0, chartCounter: savedState.chartCounter || 0, // 挂载标记,初始化阶段不触发存储逻辑 isMounted: false }; this.onAddItem = this.onAddItem.bind(this); this.onChartItem = this.onChartItem.bind(this); this.onBreakpointChange = this.onBreakpointChange.bind(this); }
- 第三步:修改
getFromLS方法,直接返回全量存储对象
export function getFromLS() { if (global.localStorage) { try { return JSON.parse(global.localStorage.getItem("rgl-8")) || {}; } catch (e) { return {}; } } return {}; }
- 第四步:修改布局变更回调,仅在组件挂载完成后才执行状态更新和存储
componentDidMount() { this.setState({ isMounted: true }); } onLayoutChange(layout, layouts) { if (this.state.isMounted) { this.setState({ layouts }, () => { this.saveAllToLS(); }); } }
- 第五步:所有元素修改操作(添加/删除元素、清空元素、拖拽新增元素)完成后,都在setState的回调中调用
saveAllToLS同步存储,示例如下:
onAddItem() { this.setState({ items: this.state.items.concat({ id: uuidV4(), i: "n" + this.state.newCounter, x: (this.state.items.length * 2) % (this.state.cols || 12), y: Infinity, w: 1, h: 1 }), newCounter: this.state.newCounter + 1 }, () => { this.saveAllToLS(); }); } // onRemoveItem、onChartItem、clearAllItem、onRemoveChartItem、onDrop方法都按上述逻辑修改即可
- 额外优化:移除重复的cols配置,static defaultProps里已经定义了cols参数,render中不需要重复传入,避免配置不一致的问题。
内容的提问来源于stack exchange,提问作者yongchang
相关产品推荐
相关产品推荐

