You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-spring:非过渡父元素下过渡组件重复渲染问题

解决react-spring移除元素时重复渲染的问题

问题核心在于useTransition对数组元素的key识别逻辑:当你把数组元素从非null改回null时,react-spring无法区分「同一位置的元素被移除」和「新元素被添加」,错误触发了重复渲染。

核心解决方案:给每个数组项绑定稳定的唯一key

固定数组每个位置的唯一标识,让react-spring能准确跟踪每个元素的进入/离开状态,而非依赖元素内容(null/非null)判断。

修改后的完整代码

HTML

<div id="app"></div>

CSS

.tiles {
  display: flex;
  gap: 10px;
  list-style: none;
  margin: 10px;
  padding: 0
}

.tile {
  height: 100px;
  width: 100px;
  border: 1px solid black;
  border-radius: 10px;
}

.card {
  height: 100%;
  width: 100%;
  background: red;
  border-radius: 10px;
}

JavaScript

const { useState } = React;
const { createRoot } = ReactDOM;

const { animated, useTransition } = ReactSpring;

const App = () => {
  return (
    <div>
      <Grid />
    </div>
  );
};

const Grid = () => {
  // 初始化数组为带固定唯一id的对象,每个位置的id不随内容变化
  const [items, setItems] = React.useState([
    { id: 1, content: null },
    { id: 2, content: null },
    { id: 3, content: null }
  ]);

  const transition = useTransition(items, {
    from: { opacity: 0, transform: "translateY(-50px)" },
    enter: { opacity: 1, transform: "translateY(0px)" },
    leave: { opacity: 0, transform: "translateY(-50px)" },
    // 指定用元素id作为跟踪key,确保稳定性
    keys: item => item.id
  });
  
  const add = () => {
    setItems(prev => prev.map(item => 
      item.id === 1 ? { ...item, content: "Card 1" } : item
    ));
  };

  const remove = () => {
    setItems(prev => prev.map(item => 
      item.id === 1 ? { ...item, content: null } : item
    ));
  };
  
  return (
    <div>
      <button onClick={ add }>Add card to first slot</button>
      <button onClick={ remove }>Remove card in first slot</button>
      <ul className="tiles">
        { transition((style, item) => (
          <li className="tile" key={item.id}>
            { item.content && (
              <animated.div className="card" style={ style }>{ item.content }</animated.div>
            ) }
          </li>
        )) }
      </ul>
    </div>
  );
};

const container = document.getElementById('app');
const root = createRoot(container);

root.render(<App />);

关键修改说明

  1. 数组结构调整:将每个元素改为包含id(固定唯一标识)和content(可null的实际内容)的对象,确保每个位置的跟踪标识稳定。
  2. useTransition配置:添加keys: item => item.id,明确告诉react-spring用id跟踪元素,而非默认的元素内容。
  3. 状态更新逻辑:用map更新指定id的元素内容,不改变数组结构和其他元素的id,保证状态变更的可预测性。

修改后,当元素被改回null时,react-spring会正确识别为同一元素的离场动画,不会触发重复渲染,动画结束后再完成元素卸载。

内容的提问来源于stack exchange,提问作者Andries

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 21:35:14