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

React Native+Reanimated动态渲染报错:Hook渲染数量不一致

解决React Native + Reanimated动态渲染时Hook数量不一致的问题

问题根源

你遇到的报错核心是违反了React Hook的核心规则:Hook必须在每次渲染时以完全相同的顺序调用。之前的写法里,你根据hand数组的长度动态生成useSharedValue数组,数组元素增减会导致Hook的调用数量前后不一致,直接触发Rendered more hooks than during the previous render错误。

两种可行解决方案

方案1:用单个useSharedValue存储所有元素的动画状态

把每个卡片的偏移量存在一个对象里,用卡片的唯一ID作为键,这样始终只使用一个useSharedValue,Hook数量不会随数组变化而改变:

import { useSharedValue, useEffect } from 'react-native-reanimated';

const CardList = ({ hand }) => {
  // 用对象存储每个卡片的偏移量,键为卡片ID
  const offsets = useSharedValue({});

  // 当hand数组更新时,为新加入的卡片初始化偏移量
  useEffect(() => {
    hand.forEach(card => {
      if (!offsets.value[card.id]) {
        // 初始化新卡片的默认偏移值
        offsets.value[card.id] = { x: 0, y: 0 };
      }
    });
  }, [hand]);

  return (
    <View>
      {hand.map(card => {
        const cardOffset = offsets.value[card.id];
        return (
          <Animated.View
            key={card.id}
            style={{
              transform: [
                { translateX: cardOffset.x },
                { translateY: cardOffset.y }
              ]
            }}
          >
            {/* 卡片内容 */}
          </Animated.View>
        );
      })}
    </View>
  );
};

方案2:将动画逻辑封装到子组件中

把每个卡片的useSharedValue放到独立的子组件里,父组件只负责循环渲染子组件。这样父组件的Hook数量始终固定,子组件的Hook由React独立管理,完全符合规则:

// 子组件:单个卡片,内部管理自己的动画状态
const CardItem = ({ card }) => {
  // 每个卡片单独拥有自己的useSharedValue
  const offset = useSharedValue({ x: 0, y: 0 });

  // 这里可以写卡片的动画逻辑,比如拖拽、入场动画等
  // ...

  return (
    <Animated.View
      style={{
        transform: [
          { translateX: offset.value.x },
          { translateY: offset.value.y }
        ]
      }}
    >
      {/* 卡片内容,比如图片、文字 */}
    </Animated.View>
  );
};

// 父组件:卡片列表
const CardList = ({ hand }) => {
  return (
    <View>
      {hand.map(card => (
        // 必须用卡片的唯一ID作为key,不能用index
        <CardItem key={card.id} card={card} />
      ))}
    </View>
  );
};

注意事项

  • 不管用哪种方案,渲染列表时必须使用卡片的唯一标识(比如card.id)作为key,不能用数组索引,否则React会错误地复用组件,导致动画状态混乱。
  • 如果卡片有删除操作,方案1里可以在useEffect里清理掉已删除卡片的偏移量,避免对象冗余:
    useEffect(() => {
      // 清理已删除卡片的偏移量
      const existingIds = hand.map(card => card.id);
      Object.keys(offsets.value).forEach(id => {
        if (!existingIds.includes(id)) {
          delete offsets.value[id];
        }
      });
      // 初始化新卡片的偏移量
      hand.forEach(card => {
        if (!offsets.value[card.id]) {
          offsets.value[card.id] = { x: 0, y: 0 };
        }
      });
    }, [hand]);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 17:55:05