反应:在元素数组中进一步渲染元素后,将剪切过渡

时间:2019-06-19 20:03:17

标签: javascript css reactjs css-transitions

在React中创建交换列表时,我遇到了一个奇怪的过渡错误。列表的工作方式很简单:单击元素(A),其背景转换为较浅的颜色,然后单击另一个(B),它们交换位置,而现在位于新位置的元素A转换回该位置。原始颜色。

至少当元素A的索引高于元素B的索引时,会发生这种情况。反之亦然,交换后的过渡将被削减。

我设法找到了使用window.requestAnimationFrame的解决方法,但这并不完美。过渡状态不会保留,这意味着它总是从完整的浅色过渡回来。这无关紧要,但这是我其他项目中的一个问题。有时,过渡也总是被切断。

代码很简单。需要注意的是,元素在交换后保留其键。我创建了a code sandbox供您玩耍。

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
}

我正在寻找比解决方法更可靠的解决方案。

所有帮助将不胜感激! :)

1 个答案:

答案 0 :(得分:0)

I've made three changes in your code,因此在交换突出显示的框时,框保持不变,然后将其关闭:

  1. 在交换功能内添加了行setSelected(index);
  2. 添加了setTimeout以延迟颜色更改。
  3. 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>;
}
相关问题