我已经对react navigation official guide中的示例进行了一些编辑,以模拟HomeScreen 1秒后的状态变化。
当父屏幕状态更改时,我不明白为什么DetailScreen无法重新渲染。有什么办法获得这种行为?
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() {
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Home Screen</Text>
<Button
title="Click"
onPress={() => {
const { value } = this.state;
this.props.navigation.navigate('Detail', { value });
setTimeout(() => {
this.setState({ value: value + 1 })
}, 1000);
}}
/>
</View>
);
}
}
class DetailScreen extends React.Component {
render() {
const { navigation } = this.props;
const value = navigation.getParam('value');
return (
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
<Text>Detail Screen</Text>
<Text>{value}</Text>
</View>
);
}
}
const RootStack = createStackNavigator(
{
Home: HomeScreen,
Detail: DetailScreen,
},
{
initialRouteName: 'Home',
}
);
const AppContainer = createAppContainer(RootStack);
export default class App extends React.Component {
render() {
return <AppContainer />;
}
}
小吃here
答案 0 :(得分:2)
您的代码为何不起作用:
您正在将value
作为导航道具从Home
传递到Details
。与常规道具不同,在Home
中更改导航道具的值不会导致导航道具本身的值发生变化。因此,如果Home
是具有Details
作为子组件的父组件,则像这样:
class HomeScreen extends React.Component {
...
<DetailsScreen
value: this.state.value
/>
...
}
然后,当this.state.value
中的Home
变化时,this.props.value
中的Details
自动变化。但是,由于Home
和Details
在堆栈导航器中具有同级关系,因此您无法将value
作为常规道具传递;将道具从Home
传递到Details
的唯一方法是,作为导航参数。问题是当您通过value
时,您已经完成以下操作:
const { value } = this.state;
this.props.navigation.navigate('Detail', { value });
更新this.state.value
中的Home
不会不会导致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将this.state.value传递给Details
。创建任何类型的导航器时,screenprops都是将变量传递给导航器中所有组件的方法。因此,您的App
组件现在将如下所示:
export default class App extends React.Component {
state = {value: 10} // state in App now instead of Home
updateValue = (value) => { // method to update App's state, passed to children
this.setState({value})
}
render() {
return <AppContainer screenProps={{
parentState: this.state,
updateValue: this.updateValue
}}/>;
}
}
更新为Home
组件
在Home
组件中唯一要更改的是onPress
函数。首先,您将不再将value
作为导航道具传递,因为您将以从App
传递给所有屏幕的screenProps而不是从{{1 }}到Home
。其次,您将调用Details
来更新this.state
中的状态,而不是更新Home
中的this.props.screenProps.updateValue()
。因此,App
组件中的onPress
看起来像这样:
Home
更新为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);
}}
组件
对Details
的唯一更改是,您将显示Details
而不是显示this.props.navigation.getParam('value')
,因为我们现在从{{ 1}},而不是来自this.props.screenProps.appState.value
的导航道具。因此,您的value
组件现在将如下所示:
App
全新代码
Home