Use multiple 'useContext' in one React component

Viewed 9348

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>
  );
}
2 Answers

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

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, despatch: setUser } = useContext(UserContext);
const { theme, despatch: setTheme } = useContext(ThemeContext);
const { state, despatch: setState } = useReducer(reducer);

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

Related