[英]React native navigation - Child not updating on parent update
I've edited a little bit the example from the react navigation official guide , in order to simulate a state change after 1 second in the HomeScreen. 为了从HomeScreen中模拟1秒后的状态变化,我已经对React Navigation官方指南中的示例进行了一些编辑。
I can't understand why the DetailScreen is not rerenderer when the parent screen state changes. 我不明白为什么父屏幕状态更改时DetailScreen无法重新渲染。 Any way to obtain such behaviour? 有什么办法获得这种行为?
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 />;
}
}
Why your code isn't working: 为什么您的代码无法正常工作:
You're passing value
as a navigation prop from Home
to Details
. 您正在将value
作为从Home
到Details
的导航道具传递。 Unlike regular props, changing the value of a navigation prop in Home
doesn't cause the value of the navigation prop itself to change. 与常规道具不同,在Home
中更改导航道具的值不会导致导航道具本身的值发生变化。 So if Home
were a parent component that had Details
as a child component, like this: 因此,如果Home
是具有Details
作为子组件的父组件,如下所示:
class HomeScreen extends React.Component {
...
<DetailsScreen
value: this.state.value
/>
...
}
then when this.state.value
changes in Home
, this.props.value
automatically changes in Details
. 然后,当this.state.value
在Home
更改时, this.props.value
将在Details
自动更改。 However, since Home
and Details
have a sibling relationship in the stack navigator, you aren't able to pass value
as a regular prop; 但是,由于Home
和Details
在堆栈导航器中具有同级关系,因此您不能将value
作为常规属性传递; the only way to pass a prop from Home
to Details
is, as you've done, as a navigation param. 将道具从“ Home
传递到“ Details
的唯一方法就是将其作为导航参数。 The problem is that when you pass value
as you've done: 问题在于,当您完成传递value
时:
const { value } = this.state;
this.props.navigation.navigate('Detail', { value });
updating this.state.value
in Home
does not cause this.props.navigation.getParam('value')
to automatically update. 在Home
中更新this.state.value
不会导致this.props.navigation.getParam('value')
自动更新。 So in your code: 因此,在您的代码中:
const value = navigation.getParam('value');
<Text>{value}</Text>
value
remains what it was when it was initially passed. value
仍然是最初通过时的value
。
SOLUTION 解
There are several possible workarounds, like manually forcing a re-render after the setTimeout
or re-structuring your component hierarchy to make Home
the parent of Details
. 有几种可能的解决方法,例如在setTimeout
之后手动强制重新渲染,或重新构造组件层次结构以将Home
作为Details
的父级。 However, I think the best way to solve the problem while preserving the structure of your app is the following: 但是,我认为在保留应用程序结构的同时解决问题的最佳方法是:
Instead of holding this.state.value
in Home
, hold it in App
. 与其在Home
中保存this.state.value
, this.state.value
在App
保存它。 This follows the general principle that it's easier for a child to update a parent's state variables (or vice versa) than it is for a component to update its sibling's state variables. 这遵循一个普遍的原则,即相对于组件更新其同级的状态变量而言,孩子更容易更新父级的状态变量(反之亦然)。
Update to App
component 更新到App
组件
Since App
is an AppContainer
, you'll need to pass this.state.value to Details
via screenprops. 由于App
是AppContainer
,因此您需要通过screenprops将this.state.value传递给Details
。 When you create any kind of navigator, screenprops are the way to pass variables to all the components in the navigator. 创建任何类型的导航器时,screenprops都是将变量传递给导航器中所有组件的方法。 So your App
component will now look like this: 因此,您的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
}}/>;
}
}
Update to Home
component 更新到Home
组件
The only thing you'll change in your Home
component will be the onPress
function. 您在Home
组件中唯一要更改的就是onPress
函数。 First, you won't pass value
as a navigation prop anymore since you'll be accessing the value as a screenProps passed from App
to all screens, rather than as a navigation prop passed from Home
to Details
. 首先,您将不再将value
作为导航道具传递,因为您将作为从App
传递到所有屏幕的screenProps而不是从Home
传递到Details
的导航道具来访问值。 Second, instead of updating this.state
of Home
you'll be calling this.props.screenProps.updateValue()
to update the state in App
. 其次,不是更新Home
this.state
而是调用this.props.screenProps.updateValue()
来更新App
的状态。 So the onPress
in your Home
component will now look like this: 因此,您的Home
组件中的onPress
现在将如下所示:
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);
}}
Update to Details
component 更新到Details
组件
The only change to Details
is that rather than displaying this.props.navigation.getParam('value')
, you'll be displaying this.props.screenProps.appState.value
since we're now getting value
from the screenProps from App
instead of as a navigation prop from Home
. 对Details
的唯一更改是,不是显示this.props.navigation.getParam('value')
,而是显示this.props.screenProps.appState.value
因为我们现在是从App
的screenProps获取value
作为Home
的导航道具。 So your Details
component will now look like this: 因此,您的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>
);
}
}
WHOLE NEW CODE 全新代码
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} // 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={{
appState: this.state,
updateValue: this.updateValue
}}/>;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.