How should the new context api work with React Native navigator?

Tom picture Tom · Jul 5, 2018 · Viewed 10.8k times · Source

I created a multiscreen app using React Navigator following this example:

import {
  createStackNavigator,
} from 'react-navigation';

const App = createStackNavigator({
  Home: { screen: HomeScreen },
  Profile: { screen: ProfileScreen },
});

export default App;

Now I'd like to add a global configuration state using the new builtin context api, so I can have some common data which can be manipulated and displayed from multiple screens.

The problem is context apparently requires components having a common parent component, so that context can be passed down to child components.

How can I implement this using screens which do not share a common parent as far as I know, because they are managed by react navigator?

Answer

dehamzah picture dehamzah · Aug 13, 2018

You can make it like this.

Create new file: GlobalContext.js

import React from 'react';

const GlobalContext = React.createContext({});

export class GlobalContextProvider extends React.Component {
  state = {
    isOnline: true
  }

  switchToOnline = () => {
    this.setState({ isOnline: true });
  }

  switchToOffline = () => {
    this.setState({ isOnline: false });
  }

  render () {
    return (
      <GlobalContext.Provider
        value={{
          ...this.state,
          switchToOnline: this.switchToOnline,
          switchToOffline: this.switchToOffline
        }}
      >
        {this.props.children}
      </GlobalContext.Provider>
    )
  }
}

// create the consumer as higher order component
export const withGlobalContext = ChildComponent => props => (
  <GlobalContext.Consumer>
    {
      context => <ChildComponent {...props} global={context}  />
    }
  </GlobalContext.Consumer>
);

On index.js wrap your root component with context provider component.

<GlobalContextProvider>
  <App />
</GlobalContextProvider>

Then on your screen HomeScreen.js use the consumer component like this.

import React from 'react';
import { View, Text } from 'react-native';
import { withGlobalContext } from './GlobalContext';

class HomeScreen extends React.Component {
  render () {
    return (
      <View>
        <Text>Is online: {this.props.global.isOnline}</Text>
      </View>
    )
  }
}

export default withGlobalContext(HomeScreen);

You can also create multiple context provider to separate your concerns, and use the HOC consumer on the screen you want.