I’m building a React application using Redux for state management. My app checks if the user is already logged in by fetching authentication data from localStorage
and dispatching it to Redux. However, I notice a brief flash of the login form on page refresh, even when the user is authenticated. Here’s my code:
function App() {
const user = useSelector(({ user }) => user);
const dispatch = useDispatch();
const [isLoading, setIsLoading] = useState(true);
async function getUserFromLocalStorage() {
setIsLoading(true);
if (!user) {
const userAuthString = window.localStorage.getItem("userAuth");
if (userAuthString !== null) {
const userAuth = JSON.parse(userAuthString);
dispatch(loginUserAuth(userAuth));
}
}
setIsLoading(false);
}
useEffect(() => {
getUserFromLocalStorage();
}, [dispatch]);
if (isLoading) {
return (
<div className='bg-background w-screen h-screen flex items-center justify-center'>
<SpinnerCircular />
</div>
);
}
if (user === null) {
return (
<div className='bg-background w-svw h-svh'>
<Notification />
<LoginForm />
</div>
);
}
return (
<div className='bg-background w-screen h-screen flex flex-col'>
<Notification />
<Routes>
<Route path="/" element={<Navbar />}>
<Route index element={<Home />} />
<Route path="/friends" element={<Friends />} />
<Route path="/exercises" element={<Exercises />} />
<Route path="/food" element={<Food />} />
<Route path="/settings" element={<Settings />} />
</Route>
</Routes>
</div>
);
}
Problem
I suspect the problem lies in how I am using useEffect. Is there a better way to manage this side-effect, particularly for state updates that rely on asynchronous operations? How can I prevent the flicker of the login form while the useEffect is fetching user data and updating the Redux state? Any suggestions would be greatly appreciated.
2
Answers
Yeah, I can see where there’s possibly a gap between the
isLoading
state being toggledfalse
and triggeringApp
to rerender beforeuser
has been updated in the Redux store and another rerender triggered with the current value.My recommendation here would be to implement actual protected routes instead of conditionally rendering your login form or app routes. Update the Redux state to start with an initially undefined
state.user
value thatApp
will dispatch an action to update to eithernull
or a defined user object that was stored in localStorage.Example:
Try passing an empty array to your useEffect. The dispatch function that you passed to the useEffect will be a new object in each re-render, which will cause repeated calls to the useEffect.
Note: I contribute to the state-machine-react library, which I find more readable and maintainable, for simple to medium-complexity projects.