Почему ваш код не работает:
Вы передаете 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
}}/>;
}
}