Частный маршрут React перенаправляется перед входом в систему при обновлении

#javascript #reactjs

Вопрос:

Я создаю веб — страницу с несколькими частными маршрутами. Если пользователь не вошел в систему, я хочу перенаправить его на домашнюю страницу. Если пользователь вошел в систему, я хочу отобразить страницу, к которой он изначально пытался получить доступ. Настройка, которую я в настоящее время использую, работает для этой цели, но всякий раз, когда пользователь входит в личный маршрут, а затем обновляет страницу, личный маршрут перенаправляет его на домашнюю страницу. К сожалению, мой loggedInProvider запускает код входа в систему ПОСЛЕ того, как частный маршрут проверяет логическое значение LoggedIn и перенаправляет их. ТАКИМ образом, технически при обновлении недостаточно быстро регистрируется человек. Есть ли способ дождаться запуска эффекта использования, вошедшего в систему, прежде чем запускать код частного маршрута?

Вот код useEffect в моем loggedInContext:

 import { useHistory } from "react-router-dom";
import React, { createContext, useState, useEffect } from "react";
import Cookie from "js-cookie";
import axios from "axios";

export const LoggedInContext = createContext();

export function LoggedInProvider(props) {
  const history = useHistory();
  const [loggedIn, setLoggedIn] = useState(false);
  const [token, setToken] = useState("");
  const [loading, setLoading] = useState();
  const [userData, setUserData] = useState({});
  //use loading variable to make splash screen - just export and write an if statement to show splashscreen if loading is true in top level app



const signUserIn = (token, userData, path = undefined) => {
    Cookie.set("token", token);
    changeLogIn(true);
    setUserData(userData.user);
    NavigateAway(path);
  };

  useEffect(() => {
    console.log("UseEffect from LoggedIn");
    setLoading(true);
    const jwt = Cookie.get("token");
    const fetchData = async () => {
      try {
        const config = {
          method: "POST",
          url: "https://prothesist-backend.herokuapp.com/api/v1/user/sign-in/token",
          headers: {
            "Content-Type": "application/json",
          },
          data: {
            token: jwt,
          },
        };
        const { data } = await axios(config);
        setLoggedIn(true);
        // setUserData(data.user);
        signUserIn(jwt, data);
        setLoading(false);
        //use userdata to fill in data
      } catch (err) {
        console.log(err);
      }
    };
    if (jwt) {
      fetchData();
    } else {
      setLoggedIn(false);
      setLoading(false);
    }
  }, []);

  const updateUserData = (data) => {
    setUserData(data);
  };
  const changeLogIn = (val) => {
    setLoggedIn(val);
    if (!val) NavigateAway("/");
  };

  const handleSignOut = () => {
    console.log("signedout");

    var myHeaders = new Headers();
    myHeaders.append("Cookie", "jwt=loggedout");

    var requestOptions = {
      method: "GET",
      headers: myHeaders,
      redirect: "follow",
    };

    fetch(
      "https://prothesist-backend.herokuapp.com/api/v1/user/logout",
      requestOptions
    )
      .then((response) => response.text())
      .then((result) => {
        setLoggedIn(false);
        Cookie.set("token", "");
        console.log(result);
      })
      .catch((error) => console.log("error", error));
  };

  const setTokens = (data) => {
    localStorage.setItem("token", JSON.stringify(data));
    setToken(data);
  };

  const NavigateAway = (path) => {
    history.push(path);
  };

  return (
    <LoggedInContext.Provider
      value={{
        userData,
        setUserData: setUserData,
        loading,
        loggedIn,
        changeLogIn,
        handleSignOut,
        token,
        setToken: setTokens,
      }}
    >
      {props.children}
    </LoggedInContext.Provider>
  );
}
 

Вот мой личный маршрут:

 import React, { useContext, useEffect } from "react";
import { Redirect, Route } from "react-router-dom";
import { LoggedInContext } from "contexts/LoggedIn.js";

export default function PrivateRoute({ children, ...rest }) {
  const { loggedIn } = useContext(LoggedInContext);
  return (
    <Route
      {...rest}
      render={({ location }) =>
        loggedIn ? (
          children
        ) : (
          <Redirect to={{ pathname: "/", state: { registerModal: true } }} />
        )
      }
    />
  );
}
 

Ответ №1:

Я бы подумал, что вы просто добавите loading чек:

 export default function PrivateRoute({ children, ...rest }) {
  const { loggedIn, loading } = useContext(LoggedInContext);
  return (
    <Route
      {...rest}
      render={({ location }) => {
        if (loggedIn) return children;
        else if (loading) return <Spinner />;
        else return (
          <Redirect to={{ pathname: "/", state: { registerModal: true } }} />
        );
      }}
    />
  );
}
 

а затем, возможно, по умолчанию loading в вашем провайдере будет установлено значение true

Комментарии:

1. Хм, похоже, у него та же проблема с этим методом.