Nidam React SPA
Continuing working on the React application we started on the registration front page. We will put everything together.
Checking if the User is logged in at Startup
Let's take a look at the top level components. AuthenticationStartup
is the component that is rendered first. Its job is very simple:
Call the resource sever public endpoint /me
. While waiting for the response show a splash screen.
When the response is returned then renders the children AppRoutes
which holds the routing.
root.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter basename="/react-ui" >
<AuthenticationStartup>
{/* emotion: this must be added to get rid of the top margin that won't go away when everything is set to margin: 0*/}
<Global styles={css` body { margin: 0; } `} />
<AppRoutes/>
</AuthenticationStartup>
</BrowserRouter>
</Provider>
</React.StrictMode>
);
If the response of /me
has populated data. Then the store property authentication.authenticated
is set to true, otherwise it says false.
We will use this property to decide whether to render private or public routes.
Also, the response is saved at the store property authentication.userInfo
.
const AuthenticationStartup = props => {
const dispatch = useDispatch();
const isLoggedInLoading = useSelector((state) => state.authentication.isLoggedInLoading);
const userInfo = useSelector((state) => state.authentication.userInfo);
const isLoggedInError = useSelector((state) => state.authentication.isLoggedInError);
const [phase, setPhase] = useState(1);
const [showSplashScreen, setShowSplashScreen] = useState(true);
useEffect(() => {
dispatch(authenticationSagas.isLoggedIn());
setPhase(2);
setShowSplashScreen(true);
}, []);
useEffect(() => {
if (phase === 2 && !isLoggedInLoading) {
if(isLoggedInError === null){
if(userInfo?.username === ""){
// if empty then unauthenticated phase 3
setPhase(3);
} else {
// if not then authenticated phase 4
setPhase(4);
// userinfo is already loaded in store, add an authenticated flag and set to true
dispatch(authenticated());
}
}
setPhase(3);
setShowSplashScreen(false);
disableSplashScreen();
}
}, [isLoggedInError, phase, isLoggedInLoading, userInfo]);
return showSplashScreen ? <LayoutSplashScreen/> : props.children;
}
export default AuthenticationStartup;
const disableSplashScreen = () => {
const splashScreen = document.getElementById('splash-screen')
if (splashScreen) {
splashScreen.style.setProperty('display', 'none')
}
}
Routing
We have two distinct routings:
- not authenticated: Sign up and error pages.
- authenticated: Secret and error pages.
const AppRoutes = () => {
const authenticated = useSelector((state) => state.authentication.authenticated);
return (<Routes>
<Route path='error/404' element={<ErrorPage />} />
{authenticated ? (
<>
<Route path="secret" element={<Private/>} />
<Route index element={<Navigate to='/secret' />} />
</>
) : (
<>
<Route path="signup" element={<SignUp/>} />
<Route index element={<Navigate to='/signup' />} />
</>
)}
<Route path='*' element={<Navigate to='/error/404' />} />
</Routes>);
}
The sign up page was explained on the Registration Front Page. Next, the login Process is discussed.