You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

React组件按条件初始化计数器生成唯一Widget ID的问题

解决react-grid-layout动态添加组件时的唯一ID生成与持久化问题

我看了你基于react-grid-layout的组件代码,已经帮你调整好了onAddItem函数的逻辑,同时修复了localStorage持久化的问题,确保ID不会重复报错。下面是修改后的完整代码:

import React from "react";
import ReactDOM from "react-dom";
import { WidthProvider, Responsive } from "react-grid-layout";
import _ from "lodash";

const ResponsiveReactGridLayout = WidthProvider(Responsive);
const originalLayout = getFromLS("layout") || [];

/**
 * This layout demonstrates how to use a grid with a dynamic number of elements.
 */
class AddRemoveLayout extends React.PureComponent {
  static defaultProps = {
    className: "layout",
    cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
    rowHeight: 100,
    onLayoutChange: function(){}
  };

  constructor(props) {
    super(props);
    // 从localStorage读取持久化的widgetID数组,为空则初始化空数组
    const savedWidgetIDs = getFromLS("widget-id") || [];
    this.state = {
      items: originalLayout.map((i, key, list) => {
        return {
          i: i.i.toString(),
          x: i.x,
          y: i.y,
          w: i.w,
          h: i.h,
          add: i.i === (list.length - 1).toString()
        };
      }),
      newCounter: savedWidgetIDs.length > 0 ? savedWidgetIDs[savedWidgetIDs.length - 1] + 1 : 0,
      layout: JSON.parse(JSON.stringify(originalLayout))
    };
    this.widgetID = savedWidgetIDs;
    this.onAddItem = this.onAddItem.bind(this);
    this.onBreakpointChange = this.onBreakpointChange.bind(this);
    this.onLayoutChange = this.onLayoutChange.bind(this);
  }

  onAddItem() {
    let newItemId;
    let updatedWidgetIDs;

    if (this.widgetID.length === 0) {
      // 数组为空时,用newCounter生成ID
      newItemId = `n${this.state.newCounter}`;
      updatedWidgetIDs = [...this.widgetID, this.state.newCounter];
      this.setState(prevState => ({
        items: prevState.items.concat({
          i: newItemId,
          x: (prevState.items.length * 2) % (this.props.cols.lg || 12),
          y: Infinity, // 放在底部
          w: 2,
          h: 2
        }),
        newCounter: prevState.newCounter + 1
      }));
    } else {
      // 数组不为空时,取最后一个值递增生成ID
      const lastId = this.widgetID[this.widgetID.length - 1];
      const nextId = lastId + 1;
      newItemId = `n${nextId}`;
      updatedWidgetIDs = [...this.widgetID, nextId];
      this.setState(prevState => ({
        items: prevState.items.concat({
          i: newItemId,
          x: (prevState.items.length * 2) % (this.props.cols.lg || 12),
          y: Infinity,
          w: 2,
          h: 2
        }),
        newCounter: nextId + 1
      }));
    }

    // 更新widgetID数组并持久化到localStorage
    this.widgetID = updatedWidgetIDs;
    saveToLS("widget-id", this.widgetID);
  }

  render() {
    return (
      <div>
        <button onClick={this.onAddItem}>Add Item</button>
        <ResponsiveReactGridLayout
          onLayoutChange={(layout) => this.onLayoutChange(layout) }
        >
          {_.map(this.state.items, el => this.createElement(el))}
        </ResponsiveReactGridLayout>
      </div>
    );
  }
}

// 通用localStorage存储函数
function saveToLS(key, value) {
  if (global.localStorage) {
    global.localStorage.setItem(key, JSON.stringify(value));
  }
}

// 通用localStorage读取函数
function getFromLS(key) {
  let value = [];
  if (global.localStorage) {
    try {
      value = JSON.parse(global.localStorage.getItem(key)) || [];
    } catch (e) {
      /* Ignore parsing errors */
    }
  }
  return value;
}

export default AddRemoveLayout;

关键改动说明:

  • 修正localStorage读写逻辑:简化了saveToLSgetFromLS函数,确保widgetID数组能正确存入和读取,避免原来的参数混乱问题。
  • 初始化时读取持久化数据:在constructor里从localStorage读取之前保存的widgetID,初始化组件时就能继承之前的ID序列,不会刷新后重置。
  • 分情况生成唯一ID
    • 当widgetID为空时,用newCounter生成n{newCounter}格式的ID,同时更新counter和widgetID数组
    • 当widgetID不为空时,取数组最后一个值加1生成新ID,同步更新counter和widgetID数组
  • 确保每次添加后持久化:每次添加新组件后,立即把更新后的widgetID数组存入localStorage,刷新页面后不会丢失序列。
  • 避免state更新冲突:使用函数式更新setState(prevState => {...})来获取最新的state值,避免异步更新导致的错误。

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

火山引擎 最新活动