React Native如何在ScreenTwo中正常显示ScreenOne更新后的points变量
问题根因
你当前的实现无法拿到更新后的值,核心有两个问题:
- ScreenOne组件内部定义的
valuePoints是函数作用域内的普通变量,每次组件渲染都会被重新初始化为0。你导出时是把初始值0赋值给了module.exports.valuePoints,后续对局部变量valuePoints的修改不会同步到导出的对象上,所以ScreenTwo拿到的永远是初始值0。 - 你尝试用localStorage拿不到值,大概率是要么存的时机不对(分数更新后没有主动调用存的方法),要么React Native环境下误用了浏览器端的localStorage(React Native本身没有localStorage API,需要用专门的AsyncStorage库)。
最优实现方案
根据你的使用场景,推荐优先选以下两种方案:
方案1:路由参数传递(适用从ScreenOne直接跳转到ScreenTwo的场景)
这是最轻量的方案,无需额外引入依赖,直接用React Navigation自带的路由传参能力即可。
ScreenOne改造代码
import { useState } from 'react' const ScreenOne = ({ navigation }) => { // 用useState托管分数,保证更新时组件可正常重渲染 const [valuePoints, setValuePoints] = useState(0) // 校验逻辑计算最终分数 let calculatedPoints = 0 if (userInput1.search('No') < 0) { console.log('Wrong answer!') } else { calculatedPoints += 10 } if (userInput2.search('Yes') < 0) { console.log('Wrong answer!') } else { calculatedPoints += 10 } // 同步更新state setValuePoints(calculatedPoints) // 跳转ScreenTwo时携带分数参数 const jumpToScreenTwo = () => { navigation.navigate('ScreenTwo', { points: valuePoints }) } return ( <ScreenContainer> <ScrollView style={{ flex: 1, width: '100%' }}> <PointsAmount> {valuePoints} </PointsAmount> {/* 跳转按钮示例,你可以替换为你自己的触发跳转的逻辑 */} <TouchableOpacity onPress={jumpToScreenTwo}> <Text>前往第二页</Text> </TouchableOpacity> </ScrollView> </ScreenContainer> ) } export default ScreenOne;
ScreenTwo改造代码
const ScreenTwo = ({ route, navigation }) => { // 从路由参数中获取分数,默认值设为0避免参数为空报错 const valuePoints = route.params?.points ?? 0 return ( <PointsContainer> <ScrollView style={{flex:1, width: '100%'}}> <TouchableOpacity onPress={() => navigation.navigate('MyTabs1')} > <ScoreCard header='Points gained' points={valuePoints} goal={100} /> </TouchableOpacity> </ScrollView> </PointsContainer> ) } export default ScreenTwo;
方案2:Context全局状态管理(适用多页面共享分数、非直接跳转的场景)
如果两个页面不是直接跳转的关系(比如是同级Tab页、多个页面都要用到分数),用React自带的Context API实现全局状态共享即可,无需引入Redux等重状态管理库。
第一步:新建全局状态文件PointsContext.js
import { createContext, useContext, useState } from 'react' const PointsContext = createContext() // 全局状态Provider,需要包裹在你的根组件外层 export const PointsProvider = ({ children }) => { const [points, setPoints] = useState(0) return ( <PointsContext.Provider value={{ points, setPoints }}> {children} </PointsContext.Provider> ) } // 自定义hooks,方便组件直接调用全局状态 export const usePoints = () => useContext(PointsContext)
第二步:根组件引入Provider
修改你的App.js入口文件,把整个应用包裹在PointsProvider里:
import { PointsProvider } from './PointsContext' import { NavigationContainer } from '@react-navigation/native' export default function App() { return ( <PointsProvider> <NavigationContainer> {/* 替换为你自己的路由配置 */} </NavigationContainer> </PointsProvider> ) }
第三步:ScreenOne中使用全局状态
import { usePoints } from './PointsContext' const ScreenOne = ({ navigation }) => { const { points, setPoints } = usePoints() // 校验逻辑计算完分数后更新全局状态 let calculatedPoints = 0 if (userInput1.search('No') < 0) { console.log('Wrong answer!') } else { calculatedPoints += 10 } if (userInput2.search('Yes') < 0) { console.log('Wrong answer!') } else { calculatedPoints += 10 } setPoints(calculatedPoints) return ( <ScreenContainer> <ScrollView style={{ flex: 1, width: '100%' }}> <PointsAmount> {points} </PointsAmount> </ScrollView> </ScreenContainer> ) } export default ScreenOne;
第四步:ScreenTwo中直接读取全局状态
import { usePoints } from './PointsContext' const ScreenTwo = ({ navigation }) => { const { points } = usePoints() return ( <PointsContainer> <ScrollView style={{flex:1, width: '100%'}}> <TouchableOpacity onPress={() => navigation.navigate('MyTabs1')} > <ScoreCard header='Points gained' points={points} goal={100} /> </TouchableOpacity> </ScrollView> </PointsContainer> ) } export default ScreenTwo;
持久化补充说明
如果需要退出应用再打开还保留分数,你可以安装@react-native-async-storage/async-storage库,在分数更新后调用AsyncStorage.setItem('user_points', String(points))存储,应用启动时读取后同步到全局状态即可。
内容的提问来源于stack exchange,提问作者edwin
相关产品推荐
相关产品推荐

