在 react-grid-layout 的布局对象中切换静态键布尔值会导致所有网格项目移动不正确
Toggling the static key boolean in layout object of a react-grid-layout causes all grid items to move incorrectly
tl;博士:
React-grid-layout incorrectly moves all grid items around when their static option is enabled and disabled (toggled). I want the grid items to be frozen in place when static, and move if and only if the user moves them with static mode disabled. An example of the problem can be found here (CodeSandbox), with a GIF example here (Imgur).
背景
我正在使用 react-grid-layout. I have a button to toggle between non-static (draggable and resizeable) and static (non-interactive) mode for all items in the grid (info about static in react-grid-layout). I am doing so with useState
and with tips from :
为我的应用制作交互式网格布局
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 和 non-static 模式之间切换时,所有值都应保持不变,每个对象中的 static
键除外。屏幕上的位置和大小也应保持不变。这使用户能够关闭 static 模式以更改网格项目的 position/size,然后将它们“冻结”在他们离开的 place/size 中。
当前(错误)行为:
我的问题是当我处于 非静态 模式时,我将网格项目拖到我想要的位置,然后切换 static 模式,他们重置到他们之前的位置。即:
我将元素 A 拖到堆栈的底部,当我打开静态模式时,它会移动到堆栈的中间,然后将其关闭 returns 元素 A到堆栈的顶部。然后,元素 A 将在中间和顶部之间循环,具体取决于静态模式是打开还是关闭。
这是我的意思的一个例子:
我试过的:
- 如代码片段(注释代码)所示,我尝试重新创建
toggleStaticMode
函数以提供更多详细信息。我做了 isStatic
状态,并在每次点击时设置它的新值。
- 我还尝试更改位置以查看是否可以在单击时看到位置更改,我可以看到。如果不对大小和位置进行任何修改,值将保持不变,但屏幕上的位置 and/or 大小会发生变化。
- 我还尝试更改每个对象的
static
值以保持 true 或 false 以记录更改。当对象 a
和 c
的 static
值为真且 b
的值为 isStatic
时,切换静态模式会更改 b
的位置,以及 a
和 c
。控制台中打印的值表示它们没有改变。
上面的 None 告诉我发生了什么或为什么会这样。文档也没有提供太多相关信息。
一个可能有效的“hackish”解决方案是使用本地 storage/cookies from 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, Whosebug */}
<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 展示我当前问题的一个完整的、有效的例子。
此示例在使用 React classes/states 而不是 useState
的方式上 不同 ,但会出现相同的问题。此示例显示切换静态模式时 size/position 值发生变化。
编辑:
Someone Special's answer got me in the right direction, however, when the columns rearrange to a smaller value than the minimum size, the items scatter upon toggle again. An example of this can be viewed here.
更新:找到您的问题。您更新了 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 数组,它在我这边有效。
Sandbox
之前:
我以前没有使用过这个 react-grid-layout,但是我看到你的 onLayout 函数如下。
onLayoutChange(layout, layouts) {
this.props.onLayoutChange(layout, layouts);
}
您使用 props 更新了您的布局,并设置了 initialprops,但这只会设置 initialProps - 它不会侦听父组件对 props 的更改。
意思是,当你使用props.onLayoutChange(从你的父组件)时,你的父组件改变了,但你的组件状态没有改变。
你可以,
- 除了 props.onLayoutChange
之外,还要在 onLayoutChange 中更新您的状态
- 使用 componentDidUpdate 更新您的状态,使其与您的父组件同步。
tl;博士:
React-grid-layout incorrectly moves all grid items around when their static option is enabled and disabled (toggled). I want the grid items to be frozen in place when static, and move if and only if the user moves them with static mode disabled. An example of the problem can be found here (CodeSandbox), with a GIF example here (Imgur).
背景
我正在使用 react-grid-layout. I have a button to toggle between non-static (draggable and resizeable) and static (non-interactive) mode for all items in the grid (info about static in react-grid-layout). I am doing so with useState
and with tips from
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 和 non-static 模式之间切换时,所有值都应保持不变,每个对象中的 static
键除外。屏幕上的位置和大小也应保持不变。这使用户能够关闭 static 模式以更改网格项目的 position/size,然后将它们“冻结”在他们离开的 place/size 中。
当前(错误)行为:
我的问题是当我处于 非静态 模式时,我将网格项目拖到我想要的位置,然后切换 static 模式,他们重置到他们之前的位置。即:
我将元素 A 拖到堆栈的底部,当我打开静态模式时,它会移动到堆栈的中间,然后将其关闭 returns 元素 A到堆栈的顶部。然后,元素 A 将在中间和顶部之间循环,具体取决于静态模式是打开还是关闭。
这是我的意思的一个例子:
我试过的:
- 如代码片段(注释代码)所示,我尝试重新创建
toggleStaticMode
函数以提供更多详细信息。我做了isStatic
状态,并在每次点击时设置它的新值。 - 我还尝试更改位置以查看是否可以在单击时看到位置更改,我可以看到。如果不对大小和位置进行任何修改,值将保持不变,但屏幕上的位置 and/or 大小会发生变化。
- 我还尝试更改每个对象的
static
值以保持 true 或 false 以记录更改。当对象a
和c
的static
值为真且b
的值为isStatic
时,切换静态模式会更改b
的位置,以及a
和c
。控制台中打印的值表示它们没有改变。
None 告诉我发生了什么或为什么会这样。文档也没有提供太多相关信息。
一个可能有效的“hackish”解决方案是使用本地 storage/cookies from 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, Whosebug */}
<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 展示我当前问题的一个完整的、有效的例子。
此示例在使用 React classes/states 而不是 useState
的方式上 不同 ,但会出现相同的问题。此示例显示切换静态模式时 size/position 值发生变化。
编辑:
Someone Special's answer got me in the right direction, however, when the columns rearrange to a smaller value than the minimum size, the items scatter upon toggle again. An example of this can be viewed here.
更新:找到您的问题。您更新了 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 数组,它在我这边有效。 Sandbox
之前:
我以前没有使用过这个 react-grid-layout,但是我看到你的 onLayout 函数如下。
onLayoutChange(layout, layouts) {
this.props.onLayoutChange(layout, layouts);
}
您使用 props 更新了您的布局,并设置了 initialprops,但这只会设置 initialProps - 它不会侦听父组件对 props 的更改。
意思是,当你使用props.onLayoutChange(从你的父组件)时,你的父组件改变了,但你的组件状态没有改变。
你可以,
- 除了 props.onLayoutChange 之外,还要在 onLayoutChange 中更新您的状态
- 使用 componentDidUpdate 更新您的状态,使其与您的父组件同步。