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

3

23

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?

Tatar answered 5/7, 2018 at 9:16 Comment(3)
You can use Redux to manage you state.Ph
Yes, thank you. I know about Redux, but supposedly the same thing can be done with the new Context api, so I'd like to do it with builtin features instead of adding an external package just for this.Tatar
i realise its a year late but i guess you could try doing this by creating a custom Navigator and passing the context providers when rendering the navigator, you can refer the doc for steps on how to create a custom navigator (reactnavigation.org/docs/en/custom-navigators.html). Please do revert is this works for you.Angelita
B
27

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.

Baggott answered 13/8, 2018 at 14:50 Comment(5)
Redux is also another and a better way to do this.Limner
You should add reasons why it’s a better as at the moment this comment is not very helpful.Moskowitz
@Dede, Thank you for your answer, but it is not completely addressing, how to use context with React Navigator, as asked in questionBhakti
Sorry to discourage, as per my reading, I see passing state from one screen to another screen is the only feasible option and use this state, like navigation.state.paramsBhakti
what about if i wanted to inject the router's props.navigation to the context api ?Lasser
E
2

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>);
    }
Engle answered 23/11, 2019 at 22:22 Comment(1)
Ah this is the closest one I found yet. What happens if you are rendering through a switchNavigator?Pneuma
W
1

https://wix.github.io/react-native-navigation/docs/third-party-react-context/

As RNN screens are not part of the same component tree, updating the values in the shared context does not trigger a re-render across all screens. However you can still use the React.Context per RNN screen component tree.

If you need to trigger a re-render across all screens, there are many popular third party libraries such as MobX or Redux.

Whatsoever answered 15/11, 2020 at 9:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.