【问题标题】:React: Transitions are cut after element re-render further in the elements arrayReact:在元素数组中进一步重新渲染元素后,转换被切断
【发布时间】:2019-06-20 04:44:41
【问题描述】:

在 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
}

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

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

【问题讨论】:

    标签: javascript css reactjs css-transitions


    【解决方案1】:

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

    1. 在交换函数中添加了setSelected(index); 行。
    2. 添加了setTimeout 以延迟颜色变化。
    3. 将map 循环内的key 更改为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>;
    }
    

    【讨论】:

    • 但是您还添加了 1s 超时。这不是我想要的工作方式,它也是一个 hack。不过,感谢您的帮助。 :)
    • @AtomHeart 对此感到抱歉。我天真地忘了提到:O 但是为什么你认为使用setTimeout 是一种黑客行为?您还试图实现哪些其他行为?
    • 转到我的代码沙箱并将索引 1 的元素与索引 0 的元素交换(按此顺序)。这就是我想要实现的行为。然后从索引 0 开始,并交换索引 1——这就是问题所在,交换后没有过渡。
    • 如果我用它来实现我想要的行为,那将是一个 hack,即将它设置为 0ms。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-12-19
    • 1970-01-01
    • 2022-01-02
    • 2021-02-03
    • 2020-09-03
    • 2018-02-25
    • 1970-01-01
    相关资源
    最近更新 更多