Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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?

like image 382
Tom Avatar asked Jul 05 '18 09:07

Tom


People also ask

Can you use Context API with react native?

React Context API provides a easy way to pass data through the component tree without having to pass props down manually at every level. You can find more about the Context API in React documentation. You can use the React Context API with React Native Navigation with a limitation.

Why we use Context API in react native?

The main purpose of using context API is avoiding 'prop drilling' – passing prop at every level. It is more like a pipeline used to pass values from one end to another. Context API provides the easiest way for passing data through the component tree so that you don't have to pass props down manually at every level.

What is a good use case for the Context API?

Some sample use cases where the Context API proves helpful are: Theming — Pass down app theme. i18n — Pass down translation messages. Authentication — Pass down current authenticated user.


2 Answers

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.

like image 91
dehamzah Avatar answered Sep 18 '22 09:09

dehamzah


This answer takes in consideration react-navigation package.

You have to wrap your App component with the ContextProvider in order to have access to your context on both screens.

    import { createAppContainer } from 'react-navigation'
    import { createStackNavigator } from 'react-navigation-stack'
    import ProfileContextProvider from '../some/path/ProfileContextProvider'

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

    const AppContainer = createAppContainer(RootStack)    
    const App = () => {
      return (
      <ProfileContextProvider>
        <AppContainer />
      </ProfileContextProvider>);
    }
like image 42
René Michel Avatar answered Sep 18 '22 09:09

René Michel