刷新页面时反应上下文未定义

React context undefined when refreshing page

我想创建一个只有经过身份验证的用户才能访问的受保护路由。它工作 BUT 当我刷新页面时上下文未定义并将用户重定向到登录页面。我真的不明白为什么会这样。

刷新页面后的控制台日志

App.js

import React, { useState, useEffect } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import Axios from "axios";
import Home from "./components/pages/Home";
import LandingPage from "./components/pages/LandingPage";
import { ProtectedRoute } from "./components/auth/ProtectedRoute";
import UserContext from "./context/UserContext";

import "./style.css";

export default function App() {
  const [userData, setUserData] = useState({
    token: undefined,
    user: undefined,
  });

  const checkLoggedIn = async () => {
    let token = localStorage.getItem("auth-token");
    if (token === null) {
      localStorage.setItem("auth-token", "");
      token = "";
    }
    const tokenRes = await Axios.post(
      "http://localhost:5000/users/tokenIsValid",
      null,
      { headers: { "x-auth-token": token } }
    );
    if (tokenRes.data) {
      const userRes = await Axios.get("http://localhost:5000/users/", {
        headers: { "x-auth-token": token },
      });
      setUserData({
        token,
        user: userRes.data,
      });
    }
  };

  useEffect(() => {
    console.log('useEffect called');

    checkLoggedIn();
  }, []);

  return (
    <>
      <BrowserRouter>
      <UserContext.Provider value={{ userData, setUserData }}>
            <Switch>
                <Route exact path="/" component={LandingPage} />
                <ProtectedRoute exact path="/home" component={Home} />
            </Switch>
        </UserContext.Provider>
      </BrowserRouter>
    </>
  );
}

ProtectedRoute.js

import React, { useContext } from "react";
import UserContext from "../../context/UserContext";
import { Route, Redirect } from "react-router-dom";

export const ProtectedRoute = ({
  component: Component,
  ...rest
}) => {
  const { userData } = useContext(UserContext);
  return (
    <Route
      {...rest}
      render={props => {
        console.log("USERDATA " + userData.user)
        console.log("TOKEN " + localStorage.getItem("auth-token"))
        if (userData.user) {
          return <Component {...props} />;
        } else {
          return (
            <Redirect
              to={{
                pathname: "/",
                state: {
                  from: props.location
                }
              }}
            />
          );
        }
      }}
    />
  );
};

编辑 过了一会儿我弄清楚了问题,这个问题在

中有解释

过了一会儿我发现了问题,这个问题在这个问题中有解释

这是我的解决方案,效果很好。

App.js

export default function App() {
  const [userData, setUserData] = useState({
    isLoggedIn: false,
    isLoading: true,
    token: undefined,
    user: undefined
  });

  const checkLoggedIn = async () => {
    const tokenRes = await validateToken();
    if (tokenRes.data) {
      const userRes = await getUser();
      let token = localStorage.getItem("auth-token");
      setUserData({
        token,
        user: userRes.data,
        isLoggedIn: true,
        isLoading: false
      });
    }
  };

  useEffect(() => {
    console.log('useEffect called');
    checkLoggedIn();
  }, []);

  console.log("APPPPPP")
  return (
    <>
      <BrowserRouter>
      <UserContext.Provider value={{ userData, setUserData }}>
            <Switch>
                <Route exact path="/" component={LandingPage} />
                <ProtectedRoute exact path="/home" component={Home} />
            </Switch>
        </UserContext.Provider>
      </BrowserRouter>
    </>
  );
}

ProtectedRoute.js

import React, {useContext} from "react";
import { Route, Redirect } from "react-router-dom";
import UserContext from "../../context/UserContext";

const ProtectedRoute = ({ component: Comp, path, ...rest }) => {
  const { userData } = useContext(UserContext);
  console.log(userData.isLoggedIn);
  return (
    <Route path={path} {...rest} 
    render={props => {  
       return userData.isLoggedIn ? (<Comp {...props} />) : (userData.isLoading ? 'Loading...' : <Redirect to="/" />)
      }}
    />
  );
};

export default ProtectedRoute;