Why does React redirect me to the main page after refreshing the page, even though the user is authenticated in a private route?

In the process of developing a private route component that restricts unauthenticated users and redirects them to the homepage, we encountered an issue upon page refresh. The problem arises when the current user variable momentarily becomes null after a refresh, triggering a redirect back to the main page. Consequently, every time a user refreshes the page, they are redirected to the main page and have to sign in again, despite being previously signed in.

// Authentication context
 const history = useHistory();
  const location = useLocation();
  const [currentUser, setCurrentUser] = useState<null | any>(null);
  const [currentClient, setCurrentClient] = useState<null | any>(null);
  const [loading, setLoading] = useState<boolean>(false);

  const context = useContext(exercisesContext);
  const _miscContext = useContext(miscContext);

  console.log(_miscContext);
  useEffect(() => {
    setLoading(true);
    //  with unsubscribe logic !!
    //const unsubscribe =
    onAuthStateChanged(auth, (user: any) => {
      console.log(user, 'test................................');
      // if (!user?.email_verified) {
      //  _miscContext.SetSnackBarMsg(true, 'Please verify your email');
      //  return;
      // }
      setCurrentUser(user);
      setLoading(false);
    });
    //return unsubscribe();
  }, []);

  const Signin = (email: string, password: string) => {
    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        const { user } = userCredential;
        console.log(userCredential.user.emailVerified, 'pppppppp');
        if (!user.emailVerified) {
          _miscContext.SetSnackBarMsg(true, 'Please verify your email');
          return;
        }
        // Signed in
        //const user = userCredential.user;
        //if (user) {
        history.push('/createtraining');
        // }
      })
      .catch((error) => {
        const errorCode = error.code;
        console.log(errorCode);
      });
  };

  const Signup = async (email: string, password: string, userType: string) => {
    await createUserWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        //email_verified;

        setDoc(doc(db, 'Data', userCredential.user.uid), {
          createdAt: Timestamp.now(),
        });

        sendEmailVerification(userCredential.user);
        _miscContext.SetSnackBarMsg(true, 'Please check your email');
      })
      .catch((error) => {
        const errorCode = error.code;
        //const errorMessage = error.message;
        console.log(errorCode);
        if (errorCode === 'auth/weak-password') {
          _miscContext.SetSnackBarMsg(true, 'Password must be at least 6 charechters.');
          history.push('/');
        }
        if (errorCode === 'auth/email-already-in-use') {
          _miscContext.SetSnackBarMsg(true, 'Email already exists.');
          history.push('/');
        }
      });
    _miscContext.SetModal(true, '', 'unit');
  };






  return (
    <authContext.Provider
      value={{
        currentUser,
        currentClient,
        loading,
        Signin,
        Signup,
      }}
    >
      {children}
    </authContext.Provider>
  );
};

// Private route component 
import React, { useContext } from 'react';
import { Redirect, Route } from 'react-router-dom';
import { authContext } from '../context/auth/AuthState';

interface Props {
  component: any;
  exact: any;
  path: any;
}

export const PrivateRoute: React.FC<Props> = ({ component: Componenet, ...rest }) => {
  const _authContext = useContext(authContext);
  const { currentUser, loading } = _authContext;
  console.log(currentUser);

  return <Route {...rest} render={(props) => (!currentUser && !loading ? <Redirect to='/' /> : <Componenet />)} />;
};

Answer №1

Challenge

The challenge we face is that both the initial states of currentUser and loading are falsy.

const [currentUser, setCurrentUser] = useState<null | any>(null);
const [loading, setLoading] = useState<boolean>(false);

As a result, when the application is loading or mounting initially, if a user tries to access a protected route, they get redirected before the Firebase authentication check can complete.

export const PrivateRoute: React.FC<Props> = ({ component: Component, ...rest }) => {
  const _authContext = useContext(authContext);
  const { currentUser, loading } = _authContext;
  console.log(currentUser);

  return (
    <Route
      {...rest}
      render={(props) => (!currentUser && !loading
        ? <Redirect to='/' />
        : <Component />
      )}
    />
  );
};

Resolution

One potential solution is to set an initial loading state of true or give an indeterminate value to currentUser that is not equivalent to your verified unauthenticated state. Then, perform an explicit check before deciding on redirecting or displaying the protected component.

For instance:

const [currentUser, setCurrentUser] = useState<null | any>();
const [loading, setLoading] = useState<boolean>(true);

...

export const PrivateRoute: React.FC<Props> = (props) => {
  const _authContext = useContext(authContext);
  const { currentUser, loading } = _authContext;
  console.log(currentUser);

  if (currentUser === undefined || loading) {
    return null; // or show loading spinner, etc...
  }

  return currentUser
    ? <Route {...props} />
    : <Redirect to='/' />;
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The React Hook useEffect is missing a dependency: 'handleLogout'. Make sure to either add it to the dependency array or remove it from the useEffect hook

import { useState, useEffect } from "react"; import LoginModal from "./LoginModal"; import { NavLink, useLocation, useNavigate } from "react-router-dom"; import { useDispatch } from "react-redux"; import { userLogout ...

Implementing TypeScript with react-router-dom v6 and using withRouter for class components

Trying to migrate my TypeScript React app to use react-router-dom version v6, but facing challenges. The official react-router-dom documentation mentions: When upgrading to v5.1, it's advised to replace all instances of withRouter with hooks. Howe ...

What should be the proper service parameter type in the constructor and where should it be sourced from?

Currently, I am faced with a situation where I have two Angular 1 services in separate files and need to use the first service within the second one. How can I properly type the first service in the constructor to satisfy TypeScript requirements and ensure ...

Combining Moralis and Vite for seamless integration with React

Struggling to integrate Moralis into my React Vite application by following the guidance provided in the Moralis documentation. However, after completing the installation process, I keep encountering an error Here is a snippet from my main.jsx file: impor ...

Challenge encountered with asynchronous angular queries

Dealing with asynchronous calls in Angular can be tricky. One common issue is getting an array as undefined due to the asynchronous nature of the calls. How can this be solved? private fetchData(id){ var array = []; this.httpClient.get('someUrl ...

What is the best way to standardize complex nested data within the ngrx/store?

Currently, I am utilizing ngrx/store with Angular 6. Within the store, there exists a deeply nested structure which I have concerns about in terms of its organization: const state = [ { aliases: ['alias1', 'alias2'], isRequir ...

Organize Dates in React Table

I need help with sorting the Date column in my code. Currently, the sorting is being done alphabetically. Here is the JSON data and code snippet: JSON [ { "date": "Jun-2022" }, { "date": "Jul-2022" } ...

``Error message "TypeError: handler is not a function" appears in Amplify deployed application, although the function works correctly when running locally

I am currently working on an app developed in Nexjs (13.4, Node 18.16) that communicates with a Lambda function through API Gateway. While the app runs smoothly locally using npm run dev, I encountered an error when trying to access the website via the Am ...

Unable to conceal adjacent element when z-index is set as 1

I encountered an issue where a modal is overlapping another element, and the close button of the underlying element has a z-index of 1. Despite creating a new modal with its own close button, the original close button remains visible on top. I attempted t ...

Steps to disable a field when its value is set from state

In my field array, I have dynamic fields being generated. My goal is to disable the input if its value has been initialized from the state. ...

What could be causing FormArrayName to consistently display as undefined in my HTML code, even when the safe-navigation operator is employed

Currently, I'm referring to the Angular Material example found at https://angular.io/api/forms/FormArrayName Upon initializing the packageForm formGroup in ngOnInit() and logging it in the console during ngAfterViewInit(), I can see that the translat ...

React Color Input: The input format should follow the pattern of "#rrggbb", with rr, gg, and bb being two-digit hexadecimal values

The code is functioning correctly and as expected. The background color of the squares changes when each input is modified, and the squares update once the button is pressed. During development, there was a moment when the warning mentioned appeared brief ...

The componentWillReceiveProps method is not triggered when a property is removed from an object prop

Just starting out with React, so I could really use some assistance from the community! I am working with a prop called 'sampleProp' which is defined as follows: sampleProp = {key:0, value:[]} When I click a button, I am trying to remo ...

Typescript on the client-side: what is the best way to eliminate circular dependencies when using the factory method design pattern?

In my code, I have implemented the factory method pattern. However, some instances using this pattern end up with circular dependencies. Removing these dependencies has proven to be a challenge for me. To illustrate, consider the following example: // fact ...

Launching a cutting-edge web application using React.js and Node.js

I'm currently developing a web application using React.js and Node.js. I'm curious about the deployment process for my web app. When running it on my local server, I need to use two servers - one for React.js and another for Node.js. Does this se ...

The result of comparing with `instanceof` in TypeScript

class Department { name: string; constructor(n: string) { this.name = n; } describe(this: Department){ console.log('department: ' +this.name); } } const frontend = new Department('frontend'); frontend.describe(); con ...

The test session failed to launch due to an error in initializing the "@wdio/cucumber-framework" module. Error message: [ERR_PACKAGE_PATH_NOT_EXPORTED]

I added @wdio/cli to my project using the command 'npm i --save-dev @wdio\cli'. Next, I ran 'npx wdio init' and chose 'cucumber', 'selenium-standalone-service', 'typescript', 'allure' along w ...

How can I define Record values in Typescript based on their specific keys?

I am working on creating a custom data structure that allows me to store values with string keys within the union string | number | boolean: type FilterKey = string; type FilterValue = string | number | boolean; type Filters<K extends FilterKey, T exten ...

Encountering an issue while attempting to test geolocation functionality in the web browser

I've been working on integrating the geolocation API into my app and came across a suitable resource at the MDN website. However, when I attempted to test for the existence of the geolocation object in the browser, I encountered this error: Server Err ...

How do I access and read a map within an array from Firebase using ReactJS?

I have an array that contains a map with two values: title and content. https://i.stack.imgur.com/WLWVG.png I am trying to read all the values in the array as if it were a map. However, I have attempted this code without success. Can anyone assist me? {d ...