为什么你的代码不能工作:
你从Home
传递value
作为导航属性到Details
。与常规属性不同,更改 Home
中导航属性的值并不会导致导航属性本身的值发生变化。因此,如果 Home
是一个有 Details
作为子组件的父组件,就像这样:
class HomeScreen extends React.Component {
...
<DetailsScreen
value: this.state.value
/>
...
}
当在Home
中更改this.state.value
时,Details
中的this.props.value
会自动更改。然而,由于Home
和Details
在堆栈导航器中是兄弟关系,你不能将value
作为普通属性传递;从Home
传递value
到Details
的唯一方法就像你已经做的那样,作为导航参数。问题在于,当像你所做的一样传递value
时:
const { value } = this.state;
this.props.navigation.navigate('Detail', { value });
在Home
中更新this.state.value
不会自动更新this.props.navigation.getParam('value')
。因此,在你的代码中:
const value = navigation.getParam('value');
<Text>{value}</Text>
value
保持其初始传递时的值。
解决方案
有几种可能的解决方法,例如在setTimeout
后手动强制重新渲染或重新构造您的组件层次结构,使Home
成为Details
的父级。但是,我认为在保留应用程序结构的同时解决问题的最佳方法如下:
不要将this.state.value
保存在Home
中,而是保存在App
中。这遵循一般原则,即一个子级更新父级的状态变量(反之亦然)比一个组件更新其兄弟节点的状态变量更容易。
更新到App
组件
由于App
是一个AppContainer
,所以您需要通过screenprops将此.state.value传递给Details
。当创建任何类型的导航器时,screenprops是将变量传递给导航器中的所有组件的方法。因此,您的App
组件现在将如下所示:
export default class App extends React.Component {
state = {value: 10}
updateValue = (value) => {
this.setState({value})
}
render() {
return <AppContainer screenProps={{
parentState: this.state,
updateValue: this.updateValue
}}/>;
}
}
更新Home
组件
您需要更改的仅是Home
组件中的onPress
函数。首先,您不再将value
作为导航属性传递,因为您将通过从App
传递给所有屏幕的screenProps
访问该值,而不是从Home
传递给Details
的导航属性。其次,您将调用this.props.screenProps.updateValue()
来更新App
中的状态,而不是更新Home
中的this.state
。因此,Home
组件中的onPress
现在看起来像这样:
onPress={() => {
this.props.navigation.navigate('Detail');
setTimeout(() => {
screenProps.updateValue(screenProps.appState.value + 1)
}, 1000);
}}
升级到“Details”组件
唯一需要更改的是在“Details”组件中,不再显示this.props.navigation.getParam('value')
,而是显示this.props.screenProps.appState.value
。因为现在我们从App
获取value
,而不是从Home
作为导航属性获取。所以,您的Details
组件现在应该如下:
class DetailScreen extends React.Component {
render() {
const { screenProps } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Detail Screen</Text>
<Text>{screenProps.appState.value}</Text>
</View>
);
}
}
全新代码
import React from 'react';
import { Button, View, Text } from 'react-native';
import { createStackNavigator, createAppContainer } from 'react-navigation';
class HomeScreen extends React.Component {
state = { value: 10 }
render() {
const { screenProps } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Click"
onPress={() => {
this.props.navigation.navigate('Detail'); // no navigation prop
setTimeout(() => {
screenProps.updateValue(screenProps.appState.value + 1) // updating state of App rather than state of Home
}, 1000);
}}
/>
</View>
);
}
}
class DetailScreen extends React.Component {
render() {
const { screenProps } = this.props;
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Detail Screen</Text>
<Text>{screenProps.appState.value}</Text>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Detail: DetailScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
state = {value: 10}
updateValue = (value) => {
this.setState({value})
}
render() {
return <AppContainer screenProps={{
appState: this.state,
updateValue: this.updateValue
}}/>;
}
}