繁体   English   中英

反应本机导航-子级不更新父级更新

[英]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作为从HomeDetails的导航道具传递。 与常规道具不同,在Home中更改导航道具的值不会导致导航道具本身的值发生变化。 因此,如果Home是具有Details作为子组件的父组件,如下所示:

class HomeScreen extends React.Component {
  ...
  <DetailsScreen
    value: this.state.value
  />
  ...
}

然后,当this.state.valueHome更改时, this.props.value将在Details自动更改。 但是,由于HomeDetails在堆栈导航器中具有同级关系,因此您不能将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.valuethis.state.valueApp保存它。 这遵循一个普遍的原则,即相对于组件更新其同级的状态变量而言,孩子更容易更新父级的状态变量(反之亦然)。

更新到App组件

由于AppAppContainer ,因此您需要通过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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM