2

I can't find a way to pass my data to all the children with React Router 6 and useContext hook. When I wrap the <Routes></Routes> with my Context.Provider and call it with the Context.Consumer inside my component an error appears:

The error: Cannot find name 'ShopContext'.

1.The App.tsx with the Routes and the Context.Provider

import React, { useState, createContext } from 'react';
import './App.scss';
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from '../../pages/Home';
import SharedLayout from '../../layouts/SharedLayout';
import Artists from '../../pages/Artists';
import Contact from '../../pages/Contact';
import NotFound from '../../pages/NotFound';
import { Shop } from '../../interfaces/Shop';
import Data from '../../data.json';


function App() {

    const [Infos] = useState<Shop>(Data)
    const ShopContext = createContext({})

    return (
        <BrowserRouter>
            <ShopContext.Provider value={Infos}>
                <Routes>
                    <Route path='/' element={<SharedLayout />}>
                        <Route index element={<Home />} />
                        <Route path='artists' element={<Artists />}/>
                        <Route path='contact' element={<Contact />}/>
                        <Route path='*' element={<NotFound />} />
                    </Route>
                </Routes>
            </ShopContext.Provider>
        </BrowserRouter>
    )}

export default App;

And the children component :

import React, { useContext } from 'react';

function Artists(){

    const shop = useContext(ShopContext)

    return <>
        Artists
    </>
}

export default Artists;

I tried:

  1. Wrapping the 1st Route containing the SharedLayout ==> Doesn't work, the Routes have to be direct children of <Routes>

  2. Wrapping every component inside every Route like this :

     <BrowserRouter>
             <Routes>
                 <Route path='/' element={
                     <ShopContext.Provider value={Infos}>
                     <SharedLayout />
                     </ShopContext.Provider>
                 }>
                     <Route index element={
                         <ShopContext.Provider value={Infos}>
                             <Home />
                         </ShopContext.Provider>
                     } />
                     <Route path='artists' element={
                         <ShopContext.Provider value={Infos}>
                             <Artists />
                         </ShopContext.Provider>
                     }/>
                     <Route path='contact' element={
    
                         <ShopContext.Provider value={Infos}>
                             <Contact />
                         </ShopContext.Provider>
                     }/>
                     <Route path='*' element={<NotFound />} />
                 </Route>
             </Routes>
     </BrowserRouter>
    

    )

Drew Reese
  • 165,259
  • 14
  • 153
  • 181

1 Answers1

1

Issue

The ShopContext React Context should be declared outside any React component. By declaring it inside App you are creating a new context every time App renders. Because ShopContext is declared inside App it isn't defined to use with the useContext hook in the routed components trying to consume the context value.

Solution

Move ShopContext into it's own file so it can be created and exported/imported for consumption.

Example:

ShopContext

import React, { useContext, useState, createContext } from 'react';

const ShopContext = createContext({});

const ShopProvider = ({ children }) => {
  const [infos, setInfos] = useState<Shop>(Data);

  ... business logic to set/update infos state, etc ...

  return (
    <ShopContext.Provider value={infos}>
      {children}
    </ShopContext.Provider>
  );
};

export useShopContext = () => useContext(ShopContext);

export default ShopProvider;

App

import ShopProvider from '../path/to/ShopProvider';

function App() {
  return (
    <BrowserRouter>
      <ShopProvider>
        <Routes>
          <Route path='/' element={<SharedLayout />}>
            <Route index element={<Home />} />
            <Route path='artists' element={<Artists />}/>
            <Route path='contact' element={<Contact />}/>
            <Route path='*' element={<NotFound />} />
          </Route>
        </Routes>
      </ShopProvider>
    </BrowserRouter>
  );
}

Artists

import { useShopContext } from '../path/to/ShopProvider';

function Artists(){
  const shop = useShopContext();

  return (
    <>
      Artists
    </>
  );
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181