Component Rendering Before useState Update

  Kiến thức lập trình

I’m encountering an issue in my React application where I make an API call to a sign-in endpoint. The response from the API returns correctly, indicating successful authentication. However, I’m facing two problems:

The apiData and isAuth states are not updating in time, causing the navigation to the sign-in page to occur before these states are updated.
Consequently, the application navigates to the sign-in page too quickly, without waiting for the state updates.

useApi hook

import axios, { AxiosResponse } from "axios";
import { useEffect, useRef, useState } from "react";

const useApi = <T,>(url: string, method: string, payload?: T) => {
  const [apiData, setApiData] = useState<AxiosResponse>();
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState();

  useEffect(() => {
    const getData = async () => {
      try {
        const response = await axios.request({
          params: payload,
          method,
          url,
        });

        setApiData(response.data);
      } catch (e) {
        setError(e.message);
      } finally {
        setLoading(true);
      }
    };

    getData();
  }, []);

  return { apiData, loading, error };
};

export default useApi;

this is the form

import { useState } from "react";
import { useNavigate } from "react-router-dom";

export const SignIn = () => {
  const [userInfo, setUserInfo] = useState({
    user: "",
    password: "",
  });

  const navigate = useNavigate();

  const submitForm = (e) => {
    e.preventDefault();
    navigate("/user/sign-in", { state: userInfo });
  };

  const updateUser = (newVal: string) => {
    setUserInfo((prev) => ({
      ...prev,
      user: newVal,
    }));
  };

  const updatePassword = (newVal: string) => {
    setUserInfo((prev) => ({
      ...prev,
      password: newVal,
    }));
  };

  return (
    <form onSubmit={(e) => submitForm(e)}>
      <label>username</label>
      <input type="text" onChange={(e) => updateUser(e.target.value)} />

      <label htmlFor="">password</label>
      <input type="password" onChange={(e) => updatePassword(e.target.value)} />

      <button type="submit">submit</button>
    </form>
  );
};

privateRoute where I check if user is auth or not

import { useEffect, useState } from "react";
import useApi from "../../api/useApi";
import { Navigate, useLocation } from "react-router-dom";
import UserDashboard from "./UserDashboard";

export const PrivateRoute = () => {
  const location = useLocation();

  const { apiData, loading, error } = useApi(
    import.meta.env.VITE_SIGN_IN,
    "GET",
    location.state,
  );

  const [isAuth, setAuth] = useState<boolean>(false);

  useEffect(() => {
    if (apiData?.status === 200) {
      console.log(apiData, "api apiData");
      setAuth(true);
    }
  }, [apiData]);

  return (
    <>
      {isAuth ? (
        <UserDashboard />
      ) : (
        <Navigate to="/sign-in" state={{ from: location.pathname }} />
      )}
    </>
  );
};

LEAVE A COMMENT