skip to Main Content

I am currently struggling with refactoring my Auth on a React/Strapi Web App. The webapp in this first draft only provides some content, protected by a login.

To realise the login I post credentials to my Strapi backend and want to store the returned jwt in local storage.

I created a useAuth hook, to handle the setting, persisting and provisioning of the auth state for the application. It should check if an auth object is stored locally and if so, return it. Otherwise it should set the auth. This custom hook is being used by a login form component.

My problem now is the following: I try to navigate to the /dashboard page after successful login using the useNavigate hook from react-router-dom.

Given when I comment out the statement navigate("/dashboard") the Auth is correctly written in local storage and I can access content. The user remains on the login page (form empty) and can navigate to otherwise protected pages.

Given when the statement is present the following happens:

  • The page reloads
  • The auth is not written to local storage
  • The user can therefore not access any protected content
  • The form is emptied

I think maybe I am using useNavigate wrong or there is an interaction with my useAuth hook that I am not accounting for.

Some help here would be much appreciated as I have struggled with this for some time now :/

useAuth Hook:

import { useEffect, useState } from "react";

const AUTH_STORAGE_KEY = "my-app-auth";

export const useAuth = () => {
  const [auth, setAuth] = useState(() => {
    try {
      const storedAuth = localStorage.getItem(AUTH_STORAGE_KEY);
      return storedAuth ? JSON.parse(storedAuth) : { user: null, accessToken: null };
    } catch (error) {
      console.error("Error parsing stored auth:", error);
      return { user: null, accessToken: null };
    }
  });

  useAuthPersistence(auth);

  return { auth, setAuth };
};

export const useAuthPersistence = (auth) => {
  useEffect(() => {
    try {
      if (auth.accessToken) {
        localStorage.setItem(AUTH_STORAGE_KEY, JSON.stringify(auth));
      } else {
        localStorage.removeItem(AUTH_STORAGE_KEY);
      }
    } catch (error) {
      console.error("Error persisting auth:", error);
    }
  }, [auth, AUTH_STORAGE_KEY]);
};

Relevant part of Login Form Component:


    import React, { useRef, useState, useEffect } from 'react';
    import { Link, useNavigate } from 'react-router-dom';
    
    import { useAuth } from '../../hooks/useAuth.js';
    
    export function SignInForm () {
        const userRef = useRef(); 
        const { setAuth } = useAuth();
        const navigate = useNavigate();

        [removed for readibility]
    
        const handleSubmit = async (e) => {
                
        [removed for readibility]
    
                if(response.ok) {
                    const data = await response.json();           
                    const user = data.user;
                    const accessToken = data.jwt;
    
                    console.log(user)
                    console.log(accessToken)
    
                    // Store the user and access token in the local storage
                    setAuth({ user, accessToken });
    
                    // Navigate to the dashboard
                    navigate("/dashboard"); 
    
                } else if (response.status === 400) {
                    [removed for readibility]

2

Answers


  1. Chosen as BEST ANSWER

    I solved my problem with some little discord sugar:

    • My Problem was, that I SET my auth by using a custom hook useAuth
    • However I GET my auth from a global context

  2. The issue might be related to the asynchronous nature of the navigate function from react-router-dom. To address this issue, you can move the navigate("/dashboard") call inside a useEffect.

    useEffect(() => {
      if (isLoading === false) {
        // Navigate to the dashboard
        navigate("/dashboard");
      }
    }, [isLoading, navigate]);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search