3

What is a good, or even conventional, way to use the multiple 'useContext' hooks in one React component. Usually I am pulling the state and dispatch from the provider like so:

const { state, dispatch } = useContext(thisIsTheContext);

Of course this means that I define the state and dispatch in the context itself.

Now I've read about some people making a sort of 'rootContext' where you can pass all state trough one Provider. However, this seems a little overkill to me.

Of course I can name state amd dispatch differently, however, I think it is the convention to just use these two when making use of the useReducer hook.

Anyone that could shed some light on this?


EDIT (as requested how the App.js component looks like):

function App() {
  return (
    <FlightDataProvider>
      <TravellerProvider>
        <Component /> // component here
      </TravellerProvider>
    </FlightDataProvider>
  );
}
4
  • 1
    Can you share your App.js root component where you provide multiple context? Commented Jul 3, 2020 at 17:51
  • @onuriltan I added my App.js to the post: it just comes down to several providers wrapping all the app components. Commented Jul 3, 2020 at 21:44
  • Can you also share one of your Provider, will help to see how you pass down values and dispatch Commented Jul 4, 2020 at 5:40
  • Posted an answer, take a look if you still having the issue Commented Jul 9, 2020 at 9:46

2 Answers 2

3

I think there is no need for rootContext. What I do is I define useReducer inside the specific Context Provider. I provide state and functions for a specific context like below.

FlightDataProvider.js

import React, { useReducer, createContext } from 'react'

const flightDataReducer = (state, action) => {
  switch (action.type) {
    case 'SET_FLIGHT_DATA':
      return {
        ...state,
        flightData: action.payload,
      }
    default:
      return state
  }
}

export const FlightDataContext = createContext();

export const FlightDataProvider = props => {
  const initialState = {
    flightData: 'flightData'
  }

  const [state, dispatch] = useReducer(flightDataReducer, initialState)

  const setFlightData = newFlightData => {
    dispatch({ type: 'SET_FLIGHT_DATA', payload: newFlightData })
  }

  return (
    <FlightDataContext.Provider
      value={{
        flightData: state.flightData,
        setFlightData
      }}>
      {props.children}
    </FlightDataContext.Provider>
  )
}

After that, if I want to subscribe to two different context in the same component, I do like this;

SomeComponent.js

import React from 'react'
import { FlightDataContext } from '...'
import { AnotherContext } from '...'

export const SomeComponent = () => {
  const { 
    flightData,
    setFlightData
  } = useContext(FlightDataContext)

  const {
    someValue
    setSomeValue
  } = useContext(AnotherContext)

  return (...)
}

PS you might want to separate flightDataReducer function, move it in another js file and import in inside FlightDataProvider.js

Sign up to request clarification or add additional context in comments.

Comments

3

If I understand your question, you are concerned about how to overcome name clashes when pulling in multiple contexts in one react component since in their original files they are all objects having the same property 'despatch'.

You can use an aspect of es6 destructuring to rename the diff context object properties right inside your component.

Like this:

const { user, dispatch: setUser } = useContext(UserContext);
const { theme, dispatch: setTheme } = useContext(ThemeContext);
const { state, dispatch: setState } = useReducer(reducer);

I chose the names setUser, setTheme, and setState arbitrarily. You can use any name you like.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.