簡體   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