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

使用Stack Navigator实现页面间卡路里数据传递的问题

解决React Native跨页面显示总卡路里数值的问题

我来帮你解决这个跨页面同步显示总卡路里的问题,这里有几个可行的方案,你可以根据自己的应用复杂度选择:

方案1:在Home页面读取AsyncStorage并监听页面聚焦

既然你已经把totalCalories存储在AsyncStorage里了,最简单的方式就是让Home页面在挂载时读取数据,并且监听页面聚焦事件,每次回到Home页面就重新获取最新值。

Home.js 示例代码:

import React, { Component } from 'react';
import { View, Text, AsyncStorage } from 'react-native';

export default class Home extends Component {
  static navigationOptions = {
    title: "Home",
  };

  constructor(props) {
    super(props);
    this.state = {
      totalCalories: 0,
    };
    // 监听页面聚焦事件,每次回到Home就刷新数据
    this.focusListener = this.props.navigation.addListener(
      'didFocus',
      () => this.getTotalCalories()
    );
  }

  componentWillUnmount() {
    // 组件卸载时移除监听,避免内存泄漏
    this.focusListener.remove();
  }

  // 从AsyncStorage读取卡路里数据
  getTotalCalories = async () => {
    try {
      const storedCalories = await AsyncStorage.getItem("totalCalories");
      if (storedCalories !== null) {
        this.setState({ totalCalories: parseInt(storedCalories) });
      }
    } catch (error) {
      console.error("读取卡路里数据失败:", error);
    }
  };

  componentDidMount() {
    // 页面首次加载时读取数据
    this.getTotalCalories();
  }

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>今日摄入总卡路里: {this.state.totalCalories}</Text>
      </View>
    );
  }
}

这个方案的优点是实现简单,不需要额外依赖;缺点是只有当Home页面被聚焦时才会更新数据,无法做到实时同步。

方案2:用React Context API实现实时状态共享

如果需要Tracker页面更新卡路里后,Home页面立刻同步显示最新值,React Context API是更合适的选择,它能让你在组件树中跨层级共享状态,不用手动传递props。

步骤1:创建卡路里状态上下文

新建CalorieContext.js文件:

import React, { createContext, Component } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

export const CalorieContext = createContext();

export class CalorieProvider extends Component {
  state = {
    totalCalories: 0,
  };

  componentDidMount() {
    // 初始化加载存储的卡路里数据
    this.loadStoredCalories();
  }

  loadStoredCalories = async () => {
    try {
      const storedCalories = await AsyncStorage.getItem("totalCalories");
      if (storedCalories !== null) {
        this.setState({ totalCalories: parseInt(storedCalories) });
      }
    } catch (error) {
      console.error("加载卡路里数据失败:", error);
    }
  };

  // 更新卡路里的统一方法
  updateCalories = async (newCalories) => {
    try {
      await AsyncStorage.setItem("totalCalories", JSON.stringify(newCalories));
      this.setState({ totalCalories: newCalories });
    } catch (error) {
      console.error("更新卡路里数据失败:", error);
    }
  };

  // 重置卡路里的方法
  resetCalories = async () => {
    try {
      await AsyncStorage.removeItem("totalCalories");
      this.setState({ totalCalories: 0 });
    } catch (error) {
      console.error("重置卡路里数据失败:", error);
    }
  };

  render() {
    return (
      <CalorieContext.Provider
        value={{
          totalCalories: this.state.totalCalories,
          updateCalories: this.updateCalories,
          resetCalories: this.resetCalories,
        }}
      >
        {this.props.children}
      </CalorieContext.Provider>
    );
  }
}

步骤2:在App根组件中包裹Provider

修改你的App.js,用CalorieProvider包裹整个导航组件:

import { CalorieProvider } from './CalorieContext';
import { NavigationContainer } from '@react-navigation/native';
// 导入你的导航栈

export default function App() {
  return (
    <CalorieProvider>
      <NavigationContainer>
        {/* 这里放你的导航栈组件 */}
      </NavigationContainer>
    </CalorieProvider>
  );
}

步骤3:修改Tracker.js使用Context更新状态

import React, { Component } from 'react';
import { CalorieContext } from './CalorieContext';
// 其他原有导入...

export default class Tracker extends Component {
  static navigationOptions = {
    title: "Tracker",
  };

  // 绑定Context
  static contextType = CalorieContext;

  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      dataSource: null,
      show: false,
      item: '',
      itemArray: [],
    };
  }

  // 修改点击食物项的逻辑,用Context的方法更新
  fetchOnPressOpacity = async (item) => {
    const newTotal = this.context.totalCalories + item.food.nutrients.ENERC_KCAL;
    await this.context.updateCalories(newTotal);
  };

  // 重置卡路里也用Context的方法
  resetCalories = async () => {
    await this.context.resetCalories();
  };

  // 原有fetchData等方法保持不变...

  render() {
    const { navigate } = this.props.navigation;
    return (
      <View style={styles.container}>
        <Button title="clear" onPress={() => this.resetCalories()} />
        {/* 直接从Context读取总卡路里 */}
        <Text> Total Calories: {this.context.totalCalories} </Text>
        {/* 原有渲染内容保持不变... */}
      </View>
    );
  }
}

步骤4:修改Home.js读取Context中的实时数据

import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { CalorieContext } from './CalorieContext';

export default class Home extends Component {
  static navigationOptions = {
    title: "Home",
  };

  static contextType = CalorieContext;

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        {/* 直接从Context获取实时更新的总卡路里 */}
        <Text>今日摄入总卡路里: {this.context.totalCalories}</Text>
      </View>
    );
  }
}

这个方案的优点是状态实时同步,Tracker页面更新后Home页面立刻刷新;适合需要实时数据同步的场景,而且不需要额外的第三方库。

小提醒:修正Tracker中的状态修改方式

你原来的代码里直接修改了this.state.totalCalories += ...,这不符合React的状态更新规范(直接修改state不会触发组件重新渲染),虽然你后面调用了this.setState({})能勉强生效,但建议用上面方案中的方式,通过setState或者Context的方法来更新状态,避免潜在的bug。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:23:10