【问题标题】:Toggling the static key boolean in layout object of a react-grid-layout causes all grid items to move incorrectly在 react-grid-layout 的布局对象中切换静态键布尔值会导致所有网格项目不正确地移动
【发布时间】:2020-10-29 18:54:52
【问题描述】:

tl;博士:

React-grid-layout 在启用和禁用(切换)静态选项时错误地移动所有网格项。我希望网格项目在静态时被冻结,并且当且仅当用户移动它们时才移动它们静态模式禁用。 An example of the problem can be found here (CodeSandbox),带有GIF example here (Imgur)


背景

我正在使用react-grid-layout 为我的应用程序制作交互式网格布局。我有一个按钮可以在 non-static(可拖动和可调整大小)和 static(非交互)模式之间切换网格中的所有项目 (info about static in react-grid-layout)。我正在使用useState 和来自this answer 的提示这样做:

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 变量中定义。在 staticnon-static 模式之间切换时,所有值都应保持不变,除了每个对象中的 static 键。屏幕上的位置和大小也应该保持不变。这使用户可以关闭 static 模式以更改网格项目的位置/大小,并打开以将它们“冻结”在它们离开它们的位置/大小。

当前(错误)行为

我的问题是,当我处于 非静态 模式时,我将网格项目拖到我想要的位置,然后打开 static 模式,它们会重置为他们以前在哪里。即:

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

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


我的尝试

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

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

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

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


使用的完整代码

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>

我还 uploaded this code to CodeSandbox 展示了我当前问题的完整工作示例。 这个例子不同在于它使用反应类/状态而不是useState,但同样的问题发生了。此示例显示了切换静态模式时大小/位置值的变化。

编辑:

Someone Special 的回答让我朝着正确的方向前进,但是,当列重新排列为小于最小大小的值时,项目再次在切换时分散。 can be viewed here 的一个例子。

【问题讨论】:

    标签: javascript reactjs next.js react-grid-layout


    【解决方案1】:

    更新:找到您的问题。您更新了 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 };
            })
          }
        });
      }
    

    通过在切换静态模式下更新 sm 数组,它可以在我这边工作。 Sandbox


    以前

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

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

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

    意思是,当你使用 props.onLayoutChange (来自你的父组件)时,你的父级发生了变化,但你的组件状态没有改变。

    你可以,

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

    componentDidUpdate

    【讨论】:

    • 更新状态 onLayoutChange 肯定有帮助,但是,当窗口宽度低于某个阈值(小于 5 列)时,项目会返回更改位置大小 切换静态模式时的位置。看看at this CodeSanbox
    • 您的示例起初对我不起作用,我必须先将 sm 布局添加到状态。我还添加了所有其他尺寸,包括xsxxsmd。它现在可以完美运行here。感谢您的时间和帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-20
    • 1970-01-01
    • 2021-05-31
    • 2017-12-27
    • 2021-02-24
    • 1970-01-01
    • 2021-11-22
    相关资源
    最近更新 更多