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

react-spring中useTransition两种写法差异及失效原因咨询

React-Spring useTransition两种写法行为不一致问题

我刚学react-spring,参考官方文档用数组解构形式写useTransition(对应代码里的transitions变量),但没法正常工作:animated.div一直处于style="opacity: 0;"状态,完全显示不出来。后来查资料找到直接传配置对象的写法(对应代码里的transitionsTest变量),这种写法能正常运行。我搞不懂这两种写法为啥结果不一样,而且检查TypeScript类型也没发现差异。


测试代码

"use client";

import React, {memo, useEffect, useState} from 'react'
import {animated, useTransition} from "@react-spring/web";


const Test = () => {
  useEffect(() => {
    changeItem()
  }, [])

  const [items, setItems] = useState<string[]>(["1", "2", "3", "4"]);

  const addItem = () => {
    const newItem = `Item ${items.length + 1}`;
    setItems([...items, newItem]);
  };

  const removeItem = () => {
    if (items.length === 0) return;
    const newItems = items.slice(0, -1);
    setItems(newItems);
  };

  const changeItem = () => {
    setItems(["1", "2", "3", "4"])
  }

  // 无法正常工作的写法
  const [transitions, api] = useTransition(items, () => ({
    from: {opacity: 0},
    enter: {opacity: 1},
    leave: {opacity: 1},
    config: {duration: 1000}
  }))

  // 正常工作的写法
  const transitionsTest = useTransition(items, {
    from: {opacity: 0},
    enter: {opacity: 1},
    leave: {opacity: 1},
    config: {duration: 1000}
  });

  return (
    <div>
      <div>
        <button onClick={addItem}>Add Item</button>
        <button onClick={removeItem}>Remove Item</button>
        <button onClick={changeItem}>Change Item</button>
      </div>
      <div>
        {transitions((style, item) => (
          <animated.div style={style}>{item}</animated.div>
        ))}
      </div>
      <hr/>
      <div>
        {transitionsTest((style, item) => (
          <animated.div style={style}>{item}</animated.div>
        ))}
      </div>
    </div>
  );
}

export default memo(Test)

依赖信息

"dependencies": {      
    "@next/mdx": "^13.4.4",
    "@react-spring/web": "^9.7.3",
    "@reduxjs/toolkit": "^1.9.7",
    "@types/node": "18.15.11",
    "@types/react": "^18.3.1",
    "@types/react-dom": "^18.3.0",
    "eslint": "8.38.0",
    "eslint-config-next": "^14.2.3",
    "immer": "^10.0.4",
    "next": "^14.2.3",
    "normalize.css": "^8.0.1",
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "react-redux": "^8.1.3",
    "redux": "^4.2.1",
    "typescript": "^5.4.5",
    "use-immer": "^0.9.0"
  },
  "devDependencies": {
    "sass": "^1.61.0"
  }

问题原因与解决方法

核心原因

数组解构的写法(返回[transitions, api])是react-spring的旧版API,在v9+版本中,它的参数顺序和新版API不同:

  • 旧版API参数顺序:useTransition(列表数据, 唯一键值函数, 配置函数/对象)
  • 你现在的写法把配置函数当成了「唯一键值函数」传入,导致react-spring无法正确识别列表项的变化,自然不会触发enter动画,元素一直停留在from状态的opacity:0。

修复方案

方案1:补全旧版API的参数

如果要保留数组解构写法,需要传入正确的唯一键值函数:

const [transitions, api] = useTransition(items, 
  item => item, // 用列表项本身作为唯一键(你的item是字符串,本身唯一)
  () => ({
    from: {opacity: 0},
    enter: {opacity: 1},
    leave: {opacity: 1},
    config: {duration: 1000}
  })
)

方案2:使用新版API(推荐)

直接传配置对象的写法是v9+推荐的新版API,更简洁不易出错,还可以在配置里指定键值:

const transitionsTest = useTransition(items, {
  keys: item => item, // 可选,若列表项本身唯一可省略,默认用索引
  from: {opacity: 0},
  enter: {opacity: 1},
  leave: {opacity: 1},
  config: {duration: 1000}
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 20:35:02