'React context API authentication not working

I'm trying to set up a simple authentication system using react's context api. I have two react pages here using react router, Login.js and App.js.

Here's App.js, I want it to use the isAuthenticated boolean from the context api to decide which page to render:

App.js:

function App() {

  const { isAuthenticated } = useContext(AuthContext);

  return (
    <div className="App">
      <AuthContextProvider>
        <Router>
          <Routes>
            <Route path="/" element={isAuthenticated ? <Home /> : <Login />} />
            <Route path="/register" element={isAuthenticated ? <Home /> : <Register />} />
          </Routes>
        </Router>
      </AuthContextProvider>
    </div>
  );
}

Here's how login.js authenticates the user:

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const { dispatch } = useContext(AuthContext);

  const handleClick = (e) => {
    e.preventDefault();
    dispatch({ type: "LOGIN_START" });
    try {
      const credentials = {
        email: email,
        password: password,
      }
      //Make login request to the server, and use the userID it sends back to authenticate the user
      //Currently has a bug where userID is blank on first call, but works on later calls
      axios.post('/auth/login', credentials)
      .then(response => {
        dispatch({ type: "LOGIN_SUCCESS", payload: response.data });
        // console.log(userID);
        // console.log(isAuthenticated);
      })
      .catch(err => { 
        console.log(err) 
        dispatch({ type: "LOGIN_FAILURE", payload: err });
      });
    }
    catch(err) {
      console.log(err);
    }
  }

Now there are 2 issues here:

  1. In login.js, when I click the login button that calls handleClick, and I do console.log(isAuthenticated), it logs false the first time. Any time after that it will log true.
  2. In App.js, isAuthenticated never changes to true, even while login.js will console.log it as true, so the user is never brought to the home page.

I've been struggling with this for a while now, and I just can't figure out what's going wrong here. I think it may have something to do with App.js not rerendering after the user logs in but I'm not sure.

I also have three files handling the authorization context. I don't think these are causing the issue but I will provide the code just in case I'm missing something

AuthContext.js:

import { createContext, useReducer } from "react";
import AuthReducer from "./AuthReducer";

const initialState = {
  userID: null,
  isAuthenticated: false,
  error: false,
}

export const AuthContext = createContext(initialState);

export const AuthContextProvider = ({ children }) => {

  const [state, dispatch] = useReducer(AuthReducer, initialState);

  return (
    <AuthContext.Provider value={{ 
      userID: state.userID, 
      isAuthenticated: state.isAuthenticated, 
      error: state.error, 
      dispatch, 
    }}>
      {children}
    </AuthContext.Provider>
  )
}

AuthActions.js:

export const LoginStart = (userCredentials) => ({
  type: "LOGIN_START",
});

export const LoginSuccess = (userID) => ({
  type: "LOGIN_SUCCESS",
  payload: userID,
  isAuthenticated: true,
});

export const LoginFailure = (error) => ({
  type: "LOGIN_FAILURE",
  payload: error,
  isAuthenticated: false,
});

AuthReducer.js:

const AuthReducer = (state, action) => {
  switch(action.type) {
    case "LOGIN_START":
      return {
        userID: null,
        isAuthenticated: false,
        error: false,
      }
    case "LOGIN_SUCCESS":
      return {
        userID: action.payload,
        isAuthenticated: true,
        error: false,
      }
    case "LOGIN_FAILURE":
      return {
        userID: null,
        isAuthenticated: false,
        error: action.payload,
      }
    default:
      return state;
  }
}

export default AuthReducer;

Any help is appreciated, thanks!



Solution 1:[1]

I figured this out, I simply had to move the AuthContext Provider out of App.js and into index.js

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 John