Search code examples
react-nativereact-navigationreact-navigation-v5

How to pass current state of App to Tab Navigation Screen


If I'm using React Navigation v5, what is the best way to pass the current state of a parent component (in my case, the main App) down through a Tab and Stack navigator to a screen that I'd like to use the current state in?

Following the documentation, I have created a stack navigator for each tab that holds the respective screens.

App.js contains a state that needs to be used for a few things. Most importantly, it will provide badge count on the Tab navigator, as well as be a source of Flatlist data on one of the tab screens.

What is the correct approach to getting the state from App all the way down to a child component in a stack navigator in a tab navigator?

App.js

const Tab = createBottomTabNavigator()

export default class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      neededArray: []
    }
  }

  const updateTheArray = (newArray) => {
    this.setState({
      neededArray: newArray
    })
  }

  componentDidMount(){
    //Listener that searches for nearby bluetooth beacons and updates the array with the passed function
    startObserver(updateTheArray)
  }

  componentWillUnmount(){
    stopObserver()
  }

  render(){
    return(
      <NavigationContainer>
        <Tab.Navigator>
          <Tab.Screen
            name = "Home"
            component = { HomeStack }/>
          <Tab.Screen
            name = "About"
            component = { AboutStack }/>

          //The Stack that contains the screen that I need to use the App's state in
          <Tab.Screen
            name = "Nearby"
            component = { NearbyStack }/>
        </Tab.Navigator>
      </NavigationContainer>
    )
  }
}

NearbyStack.js

//This stack holds the screen that I need to use the App's state in

const NearbyStackNav = createStackNav()

const NearbyStack = () => {
  return(
    <NearbyStackNav.Navigator>
      <NearbyStackNav.Screen
        name = "Nearby"
        component = { NearbyScreen }
      />
    </NearbyStackNav.Navigator>
  )
}

NearbyScreen.js

//The screen that I want to use the App's state in
const NearbyScreen = () => {
  return(
    <View>
      <FlatList
        //Where I would like to use the App's state
      />
    </View>
  )
}

Solution

  • My solution was to use React's Context API.

    BeaconContext.js - New

    import React from 'react'
    
    const BeaconContext = React.createContext()
    
    export default BeaconContext
    

    App.js - Modified

    import BeaconContext from './path/to/BeaconContext'
    
    const Tab = createBottomTabNavigator()
    
    export default class App extends React.Component {
      constructor(props){
        super(props)
        this.state = {
          neededArray: []
        }
      }
    
      const updateTheArray = (newArray) => {
        this.setState({
          neededArray: newArray
        })
      }
    
      componentDidMount(){
        startObserver(updateTheArray)
      }
    
      componentWillUnmount(){
        stopObserver()
      }
    
      render(){
        return(
          // Wrap the nav container in the newly created context!!!
    
          <BeaconContext.Provider value = { this.state.neededArray }
            <NavigationContainer>
              <Tab.Navigator>
                <Tab.Screen
                  name = "Home"
                  component = { HomeStack }/>
                <Tab.Screen
                  name = "About"
                  component = { AboutStack }/>
                <Tab.Screen
                  name = "Nearby"
                  component = { NearbyStack }/>
              </Tab.Navigator>
            </NavigationContainer>
          </BeaconContext.Provider>
        )
      }
    }
    

    NearbyStack.js - Unchanged

    const NearbyStackNav = createStackNav()
    
    const NearbyStack = () => {
      return(
        <NearbyStackNav.Navigator>
          <NearbyStackNav.Screen
            name = "Nearby"
            component = { NearbyScreen }
          />
        </NearbyStackNav.Navigator>
      )
    }
    

    NearbyScreen.js - Modified

    import BeaconContext from './path/to/BeaconContext'
    
    const NearbyScreen = () => {
      return(
        <View>
          //Wrap the component in the new context's consumer!!!
    
          <BeaconContext.Consumer>
          {
            context => <Text>{ context }</Text>
          }
          </BeaconContext.Consumer>
        </View>
      )
    }