I am new to localStorage and React Router, and my goal is: Redirect user to the "/dashboard" when he is logged in, and Redirect back to '/home' when he is logged out. Also, of course, not allowing him to go to the 'dashboard' if he is not logged in. For some reason my code in App.js not working:
function App() {
let userLogged;
useEffect(() => {
function checkUserData() {
userLogged = localStorage.getItem("userLogged");
}
window.addEventListener("storage", checkUserData);
return () => {
window.removeEventListener("storage", checkUserData);
};
}, []);
return (
<div className="App">
<React.StrictMode>
<Router>
<Routes>
<Route path="/" element={<Home />} />
{userLogged ? (
<Route path={"/dashboard"} element={<Dashboard />} />
) : (
<Route path={"/home"} element={<Home />} />
)}
</Routes>
</Router>
</React.StrictMode>
</div>
);
}
export default App;
I set it in the home and dashboard pages by localStorage.setItem('userLogged', false)
and localStorage.setItem('userLogged', true)
CodePudding user response:
You can only listen to changes in localStorage from other window/browser contexts, not from within the same browser/window context. Here it's expected the window knows its own state. In this case, you actually need some React state.
Convert the userLogged
to a React state variable and use a useEffect
hook to initialize and persist the userLogged
state to/from localStorage. Instead of conditionally rendering Route
components, create a wrapper component to read the userLogged
value from localStorage and conditionally render an Outlet
for nested/wrapped routes or a Navigate
component to redirect to your auth route to login.
Example:
import { Navigate, Outlet, useLocation } from 'react-router-dom';
const AuthWrapper = () => {
const location = useLocation(); // current location
const userLogged = JSON.parse(localStorage.getItem("userLogged"));
return userLogged
? <Outlet />
: (
<Navigate
to="/"
replace
state={{ from: location }} // <-- pass location in route state
/>
);
};
...
function App() {
const [userLogged, setUserLogged] = useState(
JSON.parse(localStorage.getItem("userLogged"))
);
useEffect(() => {
localStorage.setItem("userLogged", JSON.stringify(userLogged));
}, [userLogged]);
const logIn = () => setUserLogged(true);
const logOut = () => setUserLogged(false);
return (
<div className="App">
<React.StrictMode>
<Router>
<Routes>
<Route path="/" element={<Home logIn={logIn} />} />
<Route path={"/home"} element={<Home logIn={logIn} />} />
<Route element={<AuthWrapper />}>
<Route path={"/dashboard"} element={<Dashboard />} />
</Route>
</Routes>
</Router>
</React.StrictMode>
</div>
);
}
export default App;
Home
import { useLocation, useNavigate } from 'react-router-dom';
const Home = ({ logIn }) => {
const { state } = useLocation();
const navigate = useNavigate();
const loginHandler = () => {
// authentication logic
if (/* success */) {
const { from } = state || {};
// callback to update state
logIn();
// redirect back to protected route being accessed
navigate(from.pathname, { replace: true });
}
};
...
};
CodePudding user response:
You can render both route and use Navigate
component to redirect. Like this -
// [...]
<Route path={"/dashboard"} element={<Dashboard />} />
<Route path={"/home"} element={<Home />} />
{
userLogged ?
<Navigate to="/dashboard" /> :
<Navigate to="/home" />
}
// other routes
Whenever you logout, you need to manually redirect to the desired page using useNavigate hook.