How to render a screen based on the props from the previous one?

Viewed 35

I am creating the app in which I have a screen (SpotMapScreen) on which I am displaying "spots" on the map or on the list view, in dependence on the selected 'tab'. User can change the displaying system by clicking one of the top tabs:

enter image description here

I want also to give the user a possibility to open a certain tab by clicking on the adequate button in the previous screen (StartScreen):

enter image description here

So I am passing the param 'active' when user is clicking the one of above buttons and opening the next screen (SpotMapScreen):

                <TouchableOpacity
              style={styles.button}
              onPress={() => this.props.navigation.navigate('SpotMap', { active: 'map' })}
            >
              <Image style={[styles.sportIcon]}
                     source={require('../assets/images/ic_choose_relation.png')}/>
              <Text
                style={styles.buttonText}>{translate('startAct.btn_map')}</Text>
            </TouchableOpacity>
            <View style={styles.verticalDivision}/>
            <TouchableOpacity
              style={styles.button}
              onPress={() => this.props.navigation.navigate('SpotMap', { active: 'list' })}
            >
              <Image style={[styles.sportIcon]}
                     source={require('../assets/images/ic_choose_organized.png')}/>
              <Text
                style={styles.buttonText}>{translate('startAct.btn_list')}</Text>
            </TouchableOpacity>

On the SpotMapScreen I am getting this param from props in the constructor:

  constructor(props) {
super(props)
this.mapSupplier = new MapSupplier()
this.mapSupplier.setMyLocation(mock.myLocation)
this.state = {
  myLocation: mock.myLocation,
  active: props.navigation.state.params.active,
  filters: {},
  spots: [],
  addNewSpotModeEnabled: true,
  newSpotMarker: null,
}

}

And I am rendering the whole screen based on this 'active' variable:

  render() {
const active = this.state.active
if (active === 'map') {
  return (
    <SafeAreaView style={styles.container}>
      {this.renderTabs(active)}
      {this.renderMap()}
      {this.renderActionButton()}
    </SafeAreaView>
  )
} else {
  return (
    <SafeAreaView style={styles.container}>
      <ScrollView>
        {this.renderTabs(active)}
        {this.renderList()}
      </ScrollView>
    </SafeAreaView>
  )
}

} }

And the user have possibility to change the displaying look by clicking on the certain tab:

      handleTab = (tabKey) => {
    this.setState({ active: tabKey })
  }

  renderTabs(active) {
    const openMenu = () => {
      this.props.navigation.openDrawer()
    }
    return (
      <SafeAreaView style={styles.tabs}>
        <View style={{ flex: 0.6, alignItems: 'center', justifyContent: 'center' }}>
          <MaterialIcons name='menu' onPress={openMenu} size={18} style={{ alignSelf: 'center', paddingBottom: 10 }}/>
        </View>
        <View style={[styles.tab, active === 'map' ? styles.activeTab : null]}>
          <Feather name="map-pin" color={colors.black} size={18}
                   style={{ paddingBottom: 10, alignSelf: 'center', justifyContent: 'center' }}/>
          <Text style={[styles.tabTitle, active === 'map' ? styles.activeTabTitle : null]}
                onPress={() => this.handleTab('map')}>
            {translate('mapAct.map')}
          </Text>
        </View>
        <View style={[styles.tab, active === 'list' ? styles.activeTab : null]}>
          <Feather name="list" color={colors.black} size={18}
                   style={{ paddingBottom: 10, alignSelf: 'center', justifyContent: 'center' }}/>
          <Text style={[styles.tabTitle, active === 'list' ? styles.activeTabTitle : null]}
                onPress={() => this.handleTab('list')}>
            {translate('mapAct.list')}
          </Text>
        </View>
        <View style={{ flex: 0.6, alignItems: 'center', justifyContent: 'center' }}>
          <MaterialIcons name='filter-list' onPress={() => this.props.navigation.navigate('Filters')} size={18}
                         style={{ alignSelf: 'center', paddingBottom: 10 }}/>
        </View>
      </SafeAreaView>
    )
  }

But here is my problem, this solution is only working on the first use of the screen. When the user is going back to the StartScreen and he is clicking on one of the buttons, the constructor in the next screen (SpotMap) is not called, so it is not opening the right tab.

How can I receive the props from the StartScreen each time when I am opening next screen, not only on the first time (more like on the android OnResume() than OnCreate()). I read that I can use componentDidMount() method but it is not working for me, maybe because I am using the async componentDidMount() method version?

I would be very grateful for your help.

1 Answers

I am posting the solution for my own question because I finally found it. If you want to get props from previous screen in react-native each time when you "resume" the screen and you are using async componentDidMount() you should override method componentDidUpdate(prevProps, prevState). I added the code below to "SpotMapScreen" and it now works as expected in my question:

    componentDidUpdate(prevProps, prevState) {
    let new_active = 'map'
    if (typeof this.props.navigation.state.params != "undefined"){
      new_active = this.props.navigation.state.params.active
    }

    if (prevState.active !== new_active) {
      this.setState({
        active: new_active,
      })
    }
  }
Related