Почему ваш код не работает:
Вы передаете 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
, вам нужно будет передать this.state.value в Details
через screenprops. Когда вы создаете какой-либо навигатор, 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
в качестве навигационной опоры, так как вы будете получать доступ к значению как screenProps, передаваемому от App
ко всем экранам, а не как навигационная опора, передаваемая от 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')
вы будете отображать this.props.screenProps.appState.value
, так как теперь мы получаем value
из screenProps из App
, а не как навигационную опору из 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
}}/>;
}
}
03.06.2019