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

Animated.View与useRef在子组件间莫名共享问题求助

问题原因及解决方案

核心问题1:组件类型与钩子混用

你的JournalItem代码里同时出现了函数组件的useRef钩子和类组件的方法定义(handleDelete = (food) => {}),这会破坏钩子的作用域规则,导致所有组件实例意外共享同一个translateX引用,最终只有最后一个列表项的动画被触发。

核心问题2:Key值使用不当

列表渲染时用idx作为key,当列表项被删除后,React会复用原有组件实例,进一步加剧了ref引用混乱的问题。


修复方案(函数组件版本)

将JournalItem.js改为纯函数组件,确保每个实例拥有独立的动画引用:

import { useRef } from 'react';
import { Animated } from 'react-native';

const JournalItem = ({ food, onDelete }) => {
  // 每个组件实例会初始化独立的Animated.Value引用
  const translateX = useRef(new Animated.Value(0)).current;

  const handleDelete = () => {
    Animated.timing(translateX, {
      toValue: -width,
      duration: 350,
      useNativeDriver: false,
    }).start(() => {
      // 触发父组件的删除逻辑
      onDelete(food);
    });
  };

  return (
    <Swipeable
      renderRightActions={renderRightActions}
      overshootRight={false}
      onSwipeableOpen={handleDelete}
      rightThreshold={75}
      containerStyle={[
        {
          transform: [{ translateX }],
        },
      ]}
    >
      {/* 组件内容 */}
    </Swipeable>
  );
};

export default JournalItem;

同时修改列表渲染的key值,使用food的唯一标识(如food.id)代替索引:

{formattedJournal[meal].map((food, idx, arr) => {
  const isLast = idx === arr.length - 1;
  return (
    <View key={food.id}> {/* 改用唯一ID作为key */}
      <JournalItem
        isLast={isLast}
        idx={idx}
        food={food}
        onDelete={/* 传入父组件的删除函数 */}
      />
    </View>
  );
})}

修复方案(类组件版本)

如果坚持使用类组件,替换useRef为createRef来保证实例独立:

import { Component, createRef } from 'react';
import { Animated } from 'react-native';

class JournalItem extends Component {
  constructor(props) {
    super(props);
    // 每个类实例拥有独立的动画引用
    this.translateX = createRef(new Animated.Value(0));
  }

  handleDelete = () => {
    Animated.timing(this.translateX.current, {
      toValue: -width,
      duration: 350,
      useNativeDriver: false,
    }).start(() => {
      this.props.onDelete(this.props.food);
    });
  };

  render() {
    return (
      <Swipeable
        renderRightActions={renderRightActions}
        overshootRight={false}
        onSwipeableOpen={this.handleDelete}
        rightThreshold={75}
        containerStyle={[
          {
            transform: [{ translateX: this.translateX.current }],
          },
        ]}
      >
        {/* 组件内容 */}
      </Swipeable>
    );
  }
}

export default JournalItem;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:16:29