How can I synchronize the authenticated status of different components in React?

Viewed 48

I've been stuck in this situation for a long time. I was working on an App by React, and in my homepage, I have a navigation bar and another component. What I want to do here is when I login/log out, my navigation bar and my other components will synchronously change. But actually, when I click login/log out in my navigation bar, only the bar change, the other components stay the same until I reload the page. How can I make the login status global? So that every components can change synchronously? I really appreciate your help!

MainPage.js

const MainPage = () => {
  const [isAuth, setAuth] = React.useState(
    window.localStorage.getItem("isAuth")
  );
  const handleLogOut = () => {
    setAuth(false);
    window.dataLayer.push({
      event: "Log Out",
      user: "Anonymous",
      timezone: "Chicago",
    });
    window.localStorage.clear();
    window.alert("You have succesfully logged out!");
  };
  return (
    <div>
      {/* Navigation bar */}
      <Container
        isAuth={isAuth}
        currentPage="Main"
        onLogin={() => {
          setAuth(true);
        }}
        onLogOut={handleLogOut}
      />

      {/* Body */}

      <CardAlign>
        {food.map((foodItem) => (
          <Card foodItem={foodItem} key={`${foodItem.id}`} isAuth={isAuth} />
        ))}
      </CardAlign>

      {/* Buttons */}
      <Buttons isAuth={isAuth} currentPage="Main" />
    </div>
  );
};

isAuth and setAuth are the hooks I use to define the login state. As you can see here the isAuth didn't update synchronously in Card and Buttons when changes happened in Container

Container.js

const Container = ({ isAuth, currentPage, onLogin, onLogOut }) => {
  return (
    <Header>
      <NavbarDiv>
        {!isAuth && <Login label="Login" onLogin={onLogin} />}
        {isAuth && <LogOut label="Log Out" onLogOut={onLogOut} />}
        {isAuth && <ChangeUser />}
        {isAuth && currentPage !== "Cart" && <Cart />}
        {isAuth && currentPage !== "Profile" && <Profile />}
      </NavbarDiv>
    </Header>
  );
};

Container.js is my navigation bar, which worked properly.

I would really really appreciate your help! Please tell me what's the problem and how I can fix it! Thank you for your time!

2 Answers

Here is a working example:

const Container = ({ isAuth, onLogin, onLogOut }) => {
  //using isAuth, onLogin and onLogout from props
  return isAuth ? (
    <button onClick={onLogOut}>log out</button>
  ) : (
    <button onClick={onLogin}>log in</button>
  );
};
const Buttons = ({ isAuth }) => {
  return (
    <h4>buttons: {isAuth ? 'logged in' : 'logged out'}</h4>
  );
};
const App = () => {
  const [isAuth, setAuth] = React.useState(false);
  return (
    <div>
      <Container
        isAuth={isAuth}
        currentPage="Main"
        onLogin={() => {
          setAuth(true);
        }}
        onLogOut={() => setAuth(false)}
      />
      <Buttons isAuth={isAuth} currentPage="Main" />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

You should use a util.js file to handle all operations on login & log out, you should export a function to check the login state, is you use an internal state to handle this then you'll need to pass in deep this state as a prop to each child.

You should use a global state handler as Redux. Or use PassportJS or Iron-Session.

Related