0

tl;博士:

当启用和禁用(切换)静态选项时, React-grid-layout会错误地移动所有网格项。我希望网格项目在静态时被冻结在适当的位置,并且当且仅当用户在禁用静态模式的情况下移动它们时才移动可以在此处 (CodeSandbox) 找到问题的示例,并在此处 (Imgur)提供GIF 示例


背景

我正在使用react-grid-layout为我的应用程序制作交互式网格布局。我有一个按钮可以在网格中的所有项目的非静态(可拖动和可调整大小)和静态(非交互)模式之间切换(关于 react-grid-layout 中的静态信息)。我正在使用此答案useState中的提示和提示这样做:

var [layout, setLayout] = useState([
  { i: "a", x: 0, y: 0, w: 10, h: 4, static: false },
  { i: "b", x: 1, y: 0, w: 3, h: 2, static: false },
  { i: "c", x: 4, y: 0, w: 1, h: 2, static: false },
]);

function toggleStaticMode() {
  setLayout(
    layout.map((prevLayout) => {
      return { ...prevLayout, static: !prevLayout.static };
    })
  );
}

预期行为

网格中的每个元素都有独特的属性,这些属性定义了它在网格布局上的位置、大小等。这些在上面显示的layout变量中定义。在静态非静态模式之间切换时,所有值都应该保持不变,除了static每个对象中的键。屏幕上的位置和大小也应该保持不变。这使用户能够关闭静态模式以更改网格项目的位置/大小,并打开以将它们“冻结”在它们离开它们的位置/大小。

当前(错误)行为

我的问题是当我处于非静态模式时,我将网格项目拖到我想要的位置,然后打开静态模式,它们会重置到之前的位置。IE:

我将元素 A 拖到堆栈的底部,当我打开静态模式时,它会移动到堆栈的中间,然后将其重新关闭会将元素 A 返回到堆栈的顶部。然后元素 A 将在中间和顶部之间循环,具体取决于静态模式是打开还是关闭。

这是我的意思的一个例子:


我尝试过的

  • 如片段(注释代码)所示,我尝试重新创建该toggleStaticMode函数以提供更多详细信息。我创建了isStatic状态,并在每次点击时设置它的新值。
  • 我还尝试更改位置以查看是否可以在点击时看到位置更改,我可以。如果不对大小和位置进行任何修改,值将保持不变,但屏幕上的位置和/或大小会发生变化。
  • 我还尝试更改static每个对象的值以保持为真或假以记录更改。当 objectac's 的static值为 true 并且b's 是时isStatic,切换静态模式会改变b, 以及aand的位置c。控制台中打印的值表示它们没有改变。

以上都没有告诉我发生了什么或为什么会这样。文档也没有提供太多关于此的信息。

一种可能有效的“hackish”解决方案是使用此示例中的本地存储/cookie ,但我不想在每次用户切换静态模式时都这样做。此解决方案实际上可能无法解决此问题。

这可能是一个错误,但如果可能的话,我想找到一个更好的解决方法。


使用的完整代码

import React, {
  useState
} from "react";
import GridLayout from "react-grid-layout";

export default function Home() {
  let [layout, setLayout] = useState([{
      i: "a",
      x: 1,
      y: 0,
      w: 8,
      h: 4,
      static: false
    },
    {
      i: "b",
      x: 3,
      y: 2,
      w: 3,
      h: 2,
      static: false
    },
    {
      i: "c",
      x: 5,
      y: 4,
      w: 1,
      h: 2,
      static: false
    },
  ]);

  function printLayoutItem(val) {
    console.log(layout[val].i + ": (w: " + layout[val].w + " h: " + layout[val].h + " x: " + layout[val].x + " y: " + layout[val].y + ")");
  }

  function toggleStaticMode() {
    setLayout(
      layout.map((l) => {
        return { ...l,
          static: !l.static
        };
      })
    );
  }

  // let [isStatic, setStatic] = useState(false);

  // function toggleStaticMode() {
  //    if (isStatic) setStatic(false) 
  //    else setStatic(true);
  //    printLayoutItem(0);
  //    printLayoutItem(1);
  //    printLayoutItem(2);
  //    setLayout([
  //        { i: "a", x: 3, y: 0, w: 8, h: 4, static: isStatic },
  //        { i: "b", x: 0, y: 2, w: 3, h: 2, static:  isStatic},
  //        { i: "c", x: 5, y: 4, w: 1, h: 2, static: isStatic },
  //    ]);
  // }

  return ( <div>
    <main>{/* thanks for this beautiful Tidy, StackOverflow */}
    <button onClick ={toggleStaticMode}>
    Toggle Static Mode
    </button> 
    <GridLayout 
        className="layout"
        layout={layout}
        cols={4}
        rowHeight={100}
        width={1200}>
    <div key="a">Hello A </div> 
    <div key="b">Hello B </div> 
    <div key="c">Hello C </div> 
    </GridLayout > 
   </main> 
   </div>
  );
}
<!-- Snippet does not run correctly, please see the example below for a working example of the error occuring -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

我还将这段代码上传到 CodeSandbox,以展示我当前问题的完整工作示例。此示例在使用反应类/状态和 not 的方式上有所不同useState,但会出现相同的问题。此示例显示切换静态模式时大小/位置值的变化。

编辑:

某人 Special的回答让我朝着正确的方向前进,但是,当列重新排列为小于最小尺寸的值时,项目再次在切换时分散。一个例子可以在这里查看

4

1 回答 1

0

更新:发现你的问题。您更新了 lg 数组,但您没有更新 sm 数组。

toggleStaticMode() {
    this.setState({
      layouts: {
        lg: this.state.layouts.lg.map((l) => {
          return { ...l, static: !l.static };
        }),
        sm: this.state.layouts.sm.map((l) => {
          return { ...l, static: !l.static };
        })
      }
    });
  }

通过在 togglestaticmode 中更新 sm 数组,它对我有用。 沙盒


以前

我以前没有使用过这个 react-grid-layout,但是我看到你的 onLayout 函数如下。

  onLayoutChange(layout, layouts) {
    this.props.onLayoutChange(layout, layouts);
  }

您使用 props 更新布局,并设置 initialprops,但这仅设置 initialProps - 它不会监听来自父组件的 props 更改。

这意味着,当您使用 props.onLayoutChange (来自您的父组件)时,您的父级会更改,但您的组件状态没有更改。

你也可以,

  1. 除了 props.onLayoutChange 之外,在 onLayoutChange 中更新您的状态
  2. 使用 componentDidUpdate 更新您的状态,使其与您的父组件同步。

组件DidUpdate

于 2020-11-21T02:28:05.287 回答