Search code examples
reactjseasy-peasy

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