Search code examples
reactjsreact-router

What is the proper way to do global state?


I have an app, and I want the app component to hold the current logged in user. I have the following routes and components.

Basically, every component in my app will make use of the user object. Sure, I can pass the user as props to each and every component, but that is not elegant. What is the proper React way of sharing the user prop globally?

const App = () => {
    const [user, setUser] = useState(null);

    return (
        <Router>
            <div className="app">
                <Topbar />
                <Switch>
                    <Route path="/login" exact component={Login} />
                    <Route path="/home" exact component={Home} />
                    <Route path="/" exact component={ShopMenu} />
                    <Route path="/orders">
                        <Orders />
                    </Route>
                    <Route path="/wishlist" exact component={Wishlist} />
                    <Route path="/wallet" exact component={Wallet} />
                    <Route path="/cart" exact component={Cart} />
                </Switch>
                <BottomBar />
            </div>
        </Router>
    );
};

Solution

  • Take a look at React Context and more specifically useContext as you're using hooks.

    The idea of context is exactly that - for you to be able to share updateable state to the descendants without having to pass it from component to component (the so called "prop-drilling").

    export const UserContext = React.createContext(null);
    
    const App = () => {
      const [user, setUser] = useState(null);
    
      return (
        <Router>
          <div className="app">
            <UserContext.Provider value={{ user: user, setUser: setUser }}>
              <Topbar />
              <Switch>
                 {/* <routes>... */}
              </Switch>
              <BottomBar />
            </UserContext.Provider>
          </div>
        </Router>
      );
    };
    

    Then, in your component:

    import { UserContext } from './app';
    
    const Topbar = () => {
      const { user, setUser } = useContext(UserContext);
    
      // use `user` here
    };
    

    If you want to have access to the setter (setUser) you can pass it through the context as well.