I have an application where people can access to the website if not login, however they should be able to access to "/app"
, "/app/*"
only if authenticated. My code below works but for some reason there is half a second, or a second of the content of "/app"
shown before showing the message "you're not allowed to..."
. Any idea why is that?
import { Provider, useDispatch, useSelector } from 'react-redux';
import { useRouter } from 'next/router';
import '../styles/front.css';
import '../styles/app.css';
import React, { useEffect, useState } from 'react';
import { wrapper, store } from '../store';
import { login, logout, selectUser } from "../redux/slices/userSlice";
import { auth } from '../firebase';
function MyApp({ Component, pageProps }) {
const user = useSelector(selectUser);
const dispatch = useDispatch();
const router = useRouter();
const isAppPage = router.pathname.startsWith('/app');
const [shouldRender, setShouldRender] = useState(true); // New state variable
const [loading, setLoading] = useState(true);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((userAuth) => {
if (userAuth) {
dispatch(login({
email: userAuth.email,
uid: userAuth.uid,
displayName: userAuth.displayName,
photoUrl: userAuth.photoURL
}));
setIsAuthenticated(true);
} else {
if (isAppPage) {
setShouldRender(false);
}
dispatch(logout());
setIsAuthenticated(false);
}
setLoading(false); // Set loading to false once the authentication status is checked
});
return () => unsubscribe(); // Cleanup the event listener when the component unmounts
}, []);
return (
<Provider store={store}>
{shouldRender ? <Component {...pageProps} /> : <p>You're not allowed to access that page.</p>}
</Provider>
);
}
export default wrapper.withRedux(MyApp);
2
Answers
That is because
shouldRender
is true on first load, and after that it goes inside useEffect and get auth state inside onAuthStateChanged.you should set it to false here:
and update inside it:
Update:
You can use another state to check loaded state.
so use:
and update inside useEffect:
For render use this:
You basically need a condition with a third value that is neither "show the content" nor "you can’t see this content". Something like a "pending" state that conditionally renders neither the
Component
nor the"You're not allowed to access that page."
text.The initial
shouldRender
state matches one of these two states you don’t want to immediately render. Start withundefined
and explicitly check for this and conditionally return null or a loading indicator, etc.Example: