Correct way to provide a store to React app when using React Router

I have an issue with my store state being undefined (or something to do with the store being undefined) when I try to access the state to determine if a user is logged in.

I am using easy-peasy:

const store = createStore({
    user: { loggedIn: false },
    adduser: action((state, payload) => {
      state.user = { loggedIn: true, ...payload }
    }),
})

And I have my routing set up like this:

const App = () => {
  
  const user = useStoreState((state) => state.user)

  return (
     <StoreProvider store={store}>
      <BrowserRouter>
      
      <Routes>
        <Route path="/" element={!user.loggedIn ? <LoginScreen /> : <Dashboard />} />
        <Route path="/sign-up" element={<SignupScreen />} />
      </Routes>
      
    </BrowserRouter>
   </StoreProvider>
  )
}

Here I am trying to render the LoginScreen component if the user is not logged in, otherwise show the dashboard.

I have this error: Uncaught TypeError: Cannot read properties of undefined (reading ‘subscribe’).

It has something to do with hooks from the trace, so it must be useStoreState, at least I think so, but in any case I can’t figure this out.

Thanks for any guidance!

I have no idea what to try.

>Solution :

<StoreProvider> needs to be higher up the component tree than where you call useStoreState. I recommend you split your component into two pieces, something like this:

const App = () => {
  return (
    <StoreProvider store={store}>
      <BrowserRouter>
        <Main />
      </BrowserRouter>
    </StoreProvider>
  );
};

const Main = () => {
  const user = useStoreState((state) => state.user);
  return (
    <Routes>
      <Route
        path="/"
        element={!user.loggedIn ? <LoginScreen /> : <Dashboard />}
      />
      <Route path="/sign-up" element={<SignupScreen />} />
    </Routes>
  );
};

Leave a Reply