Javascript 意外行为:功能vs功能组件和动画

Javascript 意外行为:功能vs功能组件和动画,javascript,reactjs,Javascript,Reactjs,我显示了一个foo列表,当我点击一些链接更多的结果时,我保留了现有的foo,并将api中的新foo添加到它们中,如下面所示 const [foos, setFoos] = useState([]); ... // api call with axios ... success: (data) => { setFoos([ ...foos, ...data ]) }, 每个组件运行上面的动画 App.js ... <div className="foos-results"&g

我显示了一个foo列表,当我点击一些链接更多的结果时,我保留了现有的foo,并将api中的新foo添加到它们中,如下面所示

const [foos, setFoos] = useState([]);
...
// api call with axios
...
success: (data) => {
    setFoos([ ...foos, ...data ])
},
每个
组件运行上面的动画

App.js

...
<div className="foos-results">
    { foos.map((foo, index) => <Foo {...{ foo, index }} key={foo.id}/>) }
</div>
...
问题是,当我附加新代码时,所有
行的动画都会被触发

预期的行为是,仅为新动画触发动画,而不是以现有动画重新开始

更新

我们已经找到了问题的根源(它与
key={foo.id}
的唯一性无关)

如果我们改变

const Foo = ({ foo, index }) => <div className="circle">...</div>
constfoo=({Foo,index})=>。。。

constrenderfoo=({foo,index})=>。。。
和App.js

...
<div className="foos-results">
    { foos.map((foo, index) => renderFoo({ foo, index })) }
</div>
...
。。。
{foos.map((foo,index)=>renderFoo({foo,index}))}
...
它起作用了

那么,为什么在react中这种行为是这样的呢


这是一个基于@Jackyef代码的动画,我不认为有办法禁用此重新渲染动画,但我认为有一种解决方法可以解决此问题

正如我们所知,每个div的css每次都会被重新加载,所以我能想到的解决方案是,创建另一个css类规则(让这个类命名为“circle\u,而不是“anim”),使用与类“circle”相同的css,但没有动画,并在添加新div时,在将类名为“circle”的所有div的change类附加到“circle\u without\u anim”之前,该类将对以前的div进行更改,并将css附加到以前的div,但没有该动画,并将该新div附加到类“circle”,使其成为唯一具有动画的div

在形式上,算法如下所示:

  • 编写另一个css类(不同的名称,例如prev_circle),使用与“circle”相同的规则,但不使用动画规则
  • 在Javascript中,在将新div添加到类“circle”之前,将所有以前具有名为“circle”的类的div的类更改为新创建的没有动画规则的类“prev_circle”
  • 用类“circle”追加新div

  • 结果:这会给人一种错觉,以前的div的CSS没有被重新加载,因为CSS是相同的,但是没有动画,但是新div有不同的CSS规则(动画规则),将被重新加载。

    这是一个非常有趣的规则

    让我们看看问题中提供的答案

    应用程序中
    ,我们可以看到这一点

      const renderItems = () => (
        <div>
          {items.map((item, index) => (
            <div className="item" key={item.id}>
              <span>
                {index + 1}. {item.value}
              </span>
            </div>
          ))}
        </div>
      );
    
      const Items = () => renderItems();
    
      return (
        <div className="App">
          <h1>List of items</h1>
          <button onClick={addItem}>Add new item</button>
          <Items />
        </div>
      );
    
    您将看到一切按预期进行

    因此,总结一下:

  • 引用相等关系到在扩散时的反应
  • 组件(返回JSX的函数或类)应该是稳定的。如果它们在渲染之间更改,则由于点1的原因,React将很难执行
  • 使用此代码:

    const Items = () => renderItems();
    ...
    <Items />
    
    A和B是不同的组件,因此如果当前渲染中有
    ,请参阅
    ,以了解更多详细信息

    有两种解决方案:

    • 在渲染函数之外创建
      组件(如Jackyef建议的那样)
    • 使用渲染函数(
      {renderItems()}
      而不是

    由于您正在为每个
    Foo
    组件指定唯一的
    关键点
    ,因此React应保留已渲染列表的一部分,并防止重新触发动画。您在这里共享的代码在我看来足够正确。具有
    类的元素在哪里?可能它与css类或
    Foo
    组件内的其他内容有关。@ClaireLin在
    Foo
    组件内有
    圆圈的元素,我更新了我的问题。嗯,我看不出你的代码有任何问题。你能制作一个沙箱版本来重现这个问题吗?你能给我们看一下Foo组件的代码吗?你能确认
    Foo.id
    是否稳定吗?如果它是稳定的,react将不会重新创建
    divs
    ,动画也不会重播。下面是一个显示行为的沙盒:@Jackyef即使在您的示例中删除
    key={item.id}
    ,它仍然有效(带有警告),因此这不是
    foo.id
    稳定性的问题
    ...
    <div className="foos-results">
        { foos.map((foo, index) => renderFoo({ foo, index })) }
    </div>
    ...
    
      const renderItems = () => (
        <div>
          {items.map((item, index) => (
            <div className="item" key={item.id}>
              <span>
                {index + 1}. {item.value}
              </span>
            </div>
          ))}
        </div>
      );
    
      const Items = () => renderItems();
    
      return (
        <div className="App">
          <h1>List of items</h1>
          <button onClick={addItem}>Add new item</button>
          <Items />
        </div>
      );
    
    const Items = ({ items }) => (
      <div>
        {items.map((item, index) => (
          <div className="item" key={item.id}>
            <span>
              {index + 1}. {item.value}
            </span>
          </div>
        ))}
      </div>
    );
    
    function App() { /* App render function */}
    
    const Items = () => renderItems();
    ...
    <Items />
    
    A = () => renderItems()
    B = () => renderItems()