[英]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.