javascript - React:在元素数组中进一步重新渲染元素后,转换被切断
问题描述
在 React 中创建交换列表时,我遇到了一个奇怪的转换错误。列表的工作方式很简单:单击一个元素 (A),它的背景过渡到较浅的颜色,然后单击另一个 (B),它们交换位置,元素 A 现在位于新位置,过渡回原色。
至少当元素 A 的索引比元素 B 高时会发生这种情况。反之,交换后的转换被切断。
我设法使用 找到了解决方法window.requestAnimationFrame
,但它并不完美。过渡的状态不会被保留,这意味着它总是从完整的浅色过渡回来。在这里没那么重要,但这在我的另一个项目中是一个问题。有时过渡也会被剪掉。
代码很简单。需要注意的是元素在交换后保留了它们的键。我创建了一个代码沙箱供您玩耍。
import React, { useState } from "react";
const Item = props => {
let classes = "item";
if (props.selected) {
classes += " selected";
}
return (
<div className={classes} onClick={props.onClick}>
{props.value}
</div>
);
};
const App = () => {
const [list, setList] = useState([1, 2, 3]);
const [selected, setSelected] = useState(-1);
const select = index => {
setSelected(index);
};
const swap = index => {
const newList = [...list];
[newList[index], newList[selected]] = [newList[selected], newList[index]];
setList(newList);
setSelected(-1);
};
// The workaround that kind of works, but is not perfect.
// const swap = index => {
// const newList = [...list];
// [newList[index], newList[selected]] = [newList[selected], newList[index]];
// setList(newList);
// window.requestAnimationFrame(() => {
// setSelected(index);
// window.requestAnimationFrame(() => {
// setSelected(-1);
// });
// });
// };
const onClick = selected < 0 ? select : swap;
const items = list.map((value, index) => (
<Item
key={value}
value={value}
selected={selected === index}
onClick={onClick.bind(this, index)}
/>
));
return <div className="list">{items}</div>;
}
以下是关键的 CSS 规则:
.item {
background: #0b7189; // darker
transition: background-color 1s;
}
.item.selected {
background-color: #228cdb; //lighter
}
我正在寻找比我的解决方法更可靠的解决方案。
所有帮助将不胜感激!:)
解决方案
我在您的代码中进行了三处更改,因此在交换突出显示的框时保持不变,然后关闭:
setSelected(index);
在 swap 函数中添加了这一行。- 添加了一个
setTimeout
以延迟颜色变化。 - 将循环
key
内部更改为值,因为它必须是唯一的,因此使用索引只是一个更好的做法。map
index
function App() {
const [list, setList] = useState([1, 2, 3]);
const [selected, setSelected] = useState(-1);
const select = index => {
setSelected(index);
};
const swap = index => {
const newList = [...list];
[newList[index], newList[selected]] = [newList[selected], newList[index]];
setList(newList);
// This was added in order to keep the highlight after swap.
// Note that it takes a second to take place
setSelected(index);
// And this was added in order to allow the colour to lighten,
// before returning to the original colour
setTimeout(() => setSelected(-1), 1000);
};
const onClick = selected < 0 ? select : swap;
const items = list.map((value, index) => (
<Item
key={index}
value={value}
selected={selected === index}
onClick={onClick.bind(this, index)}
/>
));
return <div className="list">{items}</div>;
}
推荐阅读
- python - Python ElementTree XML:添加外部链接
- ruby-on-rails - 在 Rails 数据库中保存用户的 pushSubscription 信息?
- configuration - WOSERVICEADDRESS X & Y:区分来源(SA 与用户定义)
- c# - 在进一步处理之前实现比较两个字符串的逻辑
- python - 需要在项目根目录之外有烧瓶静态文件夹
- c# - 如何将一个滚动条组合到多个富文本框
- oauth-2.0 - 从 intuit quickbooks 获取令牌时的 InvalidFieldFormat
- java - 如何从 URL 获取动态查询文本?
- regex - 正则表达式仅最后匹配
- excel - 当代码因 VBA 错误而失败时,如何保护工作表?