Javascript 意外行为:功能vs功能组件和动画
我显示了一个foo列表,当我点击一些链接更多的结果时,我保留了现有的foo,并将api中的新foo添加到它们中,如下面所示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
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 在形式上,算法如下所示:
结果:这会给人一种错觉,以前的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>
);
您将看到一切按预期进行
因此,总结一下:
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()