[英]React native navigation - Child not updating on parent update
为了从HomeScreen中模拟1秒后的状态变化,我已经对React Navigation官方指南中的示例进行了一些编辑。
我不明白为什么父屏幕状态更改时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 />;
}
}
零食在这里
为什么您的代码无法正常工作:
您正在将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 });
在Home
中更新this.state.value
不会导致this.props.navigation.getParam('value')
自动更新。 因此,在您的代码中:
const value = navigation.getParam('value');
<Text>{value}</Text>
value
仍然是最初通过时的value
。
解
有几种可能的解决方法,例如在setTimeout
之后手动强制重新渲染,或重新构造组件层次结构以将Home
作为Details
的父级。 但是,我认为在保留应用程序结构的同时解决问题的最佳方法是:
与其在Home
中保存this.state.value
, this.state.value
在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而不是从Home
传递到Details
的导航道具来访问值。 其次,不是更新Home
this.state
而是调用this.props.screenProps.updateValue()
来更新App
的状态。 因此,您的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);
}}
更新到Details
组件
对Details
的唯一更改是,不是显示this.props.navigation.getParam('value')
,而是显示this.props.screenProps.appState.value
因为我们现在是从App
的screenProps获取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} // 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.