Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to use multiple context providers in ReactNative

I am having an app in which I am using 3 Context Provider. For the app to work, I have to wrap <App/> in all these providers. As my app grows I am expecting to have a few more providers for more types of data I have to connect with. I have already started to feel that there may be a better way to pass providers into the <App />.

My App.js Code:

import React from 'react';
import { createStackNavigator } from 'react-navigation-stack';
import { createAppContainer } from 'react-navigation';
import { Provider as BlogProvider} from './src/context/BlogContext';
import { Provider as VehicleProvider} from './src/context/VehicleContext';
import { Provider as AuthProvider} from './src/context/AuthContext';

import IndexScreen from './src/screens/IndexScreen';
import ShowScreen from './src/screens/ShowScreen';
import CreateScreen from './src/screens/CreateScreen';
import EditScreen from './src/screens/EditScreen';
import VehicleScreen from './src/screens/VehicleScreen';

const navigator = createStackNavigator(
  {
    Index: IndexScreen,
    Show: ShowScreen,
    Create: CreateScreen,
    Edit: EditScreen,
    Debug: DebugScreen,
    Vehicle: VehicleScreen,

  },
  {
    initialRouteName: 'Index',
    defaultNavigationOptions: {
      title: 'Main'
    }
  }
);

const App = createAppContainer(navigator);

export default () => {
  return (
    <BlogProvider>
      <VehicleProvider>
        <AuthProvider>
             <App />
        </AuthProvider>
      </VehicleProvider>
    </BlogProvider>
  );
};

Some of the questions I have are:

  1. Is there a better way to use multiple context providers in an App.
  2. Does the order in which these providers are nested have any impact on the App?
  3. Can we skip adding provider in <App/> and instead import them in a any screen where it's required and wrap that screen element in it?
like image 316
esafwan Avatar asked Mar 08 '20 18:03

esafwan


People also ask

Can you use multiple React context providers?

We can pass in anything we want to the value prop of the context provider component. So sharing multiple states with one provider is no problem. We create the CountContext with the React.

Can you have multiple contexts React?

Consuming Multiple Contexts To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree. If two or more context values are often used together, you might want to consider creating your own render prop component that provides both.

How do I use multiple useContext?

You can use an aspect of es6 destructuring to rename the diff context object properties right inside your component. Like this: const { user, despatch: setUser } = useContext(UserContext); const { theme, despatch: setTheme } = useContext(ThemeContext); const { state, despatch: setState } = useReducer(reducer);


2 Answers

I won't answer in order it's asked.

Answer 3

If a provider ONLY provides context for a specific Component, you should import and use it in that Component. DO NOT wrap App with it.

The reason is whenever provider is updated, every consumer will be re-render, you can't no use React.memo or ReactPureComponent or shouldComponentUpdate to stop it. You should not overuse context

const Root = () => {
  return (
    <AppProvider>
      <ComponentProvider>
        <App/>
      <ComponentProvider>
    </AppProvider>
  )
}

const App = () => {
  return (
    <>
      <ComponentA/>
      <ComponentB/>
    <>
  )
}

const ComponentContext = createContext()
const ComponentProvider = ({ children }) => {
  // If any value here is updated --> all consumer will be render
  // --> App re-render --> ComponentA and ComponentB re-render
  return (
    <ComponentContext.Provider value={{ value1, value2, value }}>
      {children}
    </ComponentContext.Provider>
  )
}

You should do this instead

const Root = () => {
  <AppProvider>
    <App/>
  </AppProvider>
}

const App = () => {
  return (
   <>
    <ComponentA/>
    <ComponentB/>
   <>
  )
}

const ComponentA = () => {
  return (
    <ComponentProvider>
      <OtherComponent/>
    <ComponentProvider>
   )
}

const ComponentContext = createContext()
const ComponentProvider = ({ children }) => {
  // If any value here is updated --> all consumer (ComponentA only) will be render
  return (
    <ComponentContext.Provider value={{ value1, value2, value3 }}>
      {children}
    </ComponenContext.Provider>
  )
}

Answer 1

Answer 3 can be the answer for this, use context in the right place (For the Components which consume the context only. DO NOT randomly every context at App level). If your context is frequently updated, I recommend not to use other ways so you can use React.memo or PureComponent or shouldComponentUpdate to prevent unwanted re-render to optimise performance.

Answer 2

The order doesn't impact the App.

like image 74
Tony Nguyen Avatar answered Oct 21 '22 21:10

Tony Nguyen


  1. I'm not sure what you mean with "better". If you just want to clean up your App component, you can abstract the Provider rendering into a separate function. This or this might help you accomplish it according to your needs

  2. If, like your example, you wrap your entire application with all Providers and they are independent of each other, then the order would not matter. Otherwise they behave no different than other components, only children have access to its data and the data flow is unidirectional.

  3. Yes, there is no need to provide all data to your entire application.

like image 27
hotpink Avatar answered Oct 21 '22 22:10

hotpink