React 组件中的代码不是 运行

Code not running inside a React component

我正在创建一个 React 应用程序,我正在尝试保护密码授权背后的一些路由。

我处理这个问题的组件如下:

(ProtectedRoute.js)

export default function ProtectedRoute({ code, redirect_path = '/login' }) {

    if (code === 401) return <Navigate to={redirect_path} replace/>;
    return <Outlet/>;

}

我需要做的就是传递我的后端返回的 HTTP 状态代码,如果它对应于未经授权的响应,那么它会要求用户登录,否则允许他们通过。

我通过以下方式从 App.js 查询我的后端:

(App.js)

export default function App() {

    let [status, setStatus] = useState(401);
    useEffect(() => {
        fetch(
            'http://localhost:5000/auth',
            {
                method: 'GET',
                mode: 'cors',
                headers: {
                    'id_token': sessionStorage.getItem('id_token')
                }
            }
        )
            .then(response => response.status)
            .then(status => setStatus(status));
    }, []);
    console.log('status=' + status);

    return (
        <div className="App">
            <Navbar is_logged_in={status === 200}/>
            <ToastContainer/>
            <Routes>
                <Route index element={<Home/>}/>
                <Route path="/vehicle/:id" element={<EV/>}/>
                <Route element={<ProtectedRoute code={status}/>}>
                    <Route path="/add" element={<AddEV/>}/>
                </Route>
                <Route path="/filter" element={<Home/>}/>
                <Route path="/compare" element={<Home/>}/>
                <Route path="/login" element={<LoginRegister type="login"/>}/>
                <Route path="/register" element={<LoginRegister type="register"/>}/>
                <Route path="/logout" element={<Logout/>}/>
                <Route path="*" element={<p>Nothing here: 404!</p>}/>
            </Routes>
        </div>
    );
}

除一个问题外,此方法有效。当用户被发送到登录页面并成功通过身份验证时,他们将被发送回索引。此时,我希望 useEffect 钩子中的代码触发并更新 status.

的值

相反,没有任何反应。如果我手动刷新页面然后代码被触发并且一切都按照我期望的方式发生。

很明显思路是对的,但是实现是错误的。我想要实现的目标是可能的吗?如果是这样我应该怎么做?

提前感谢您的建议。

useEffect 有一个空的依赖项,所以它只在 App 组件挂载时运行一次。这就是为什么它在您重新加载页面时“有效”的原因。它重新加载应用程序,即重新安装 App 组件并调用 useEffect 挂钩回调。

通常将“auth”状态抽象到 React 上下文中,以便在必要时由应用程序访问,例如在尝试访问受保护的路由或记录日志时 in/out。

示例:

import { createContext, useContext, useState } from 'react';

const AuthContext = createContext({
  checkAuthStatus: () => {},
  status: 401,
  setStatus: () => {},
});

const useAuth = () => useContext(AuthContext);

const AuthProvider = ({ children }) => {
  const [status, setStatus] = useState(401);

  const checkAuthStatus = () => {
    fetch(
      'http://localhost:5000/auth',
      {
        method: 'GET',
        mode: 'cors',
        headers: {
          'id_token': sessionStorage.getItem('id_token')
        }
      }
    )
      .then(response => response.status)
      .then(status => setStatus(status));
  };

  return (
    <AuthContext.Provider value={{ checkAuthStatus, status, setStatus }}>
      {children}
    </AuthContext.Provider>
  );
};

export default AuthProvider;
export {
  AuthContext,
  useAuth
};

...

包装 App 组件。

import AuthProvider from "../path/to/AuthProvider";

...

<AuthProvider>
  <App />
</AuthProvider>

使用 useAuth 挂钩访问 status 和状态更新函数。

export default function ProtectedRoute({ redirect_path = '/login' }) {
  const { status } = useAuth();

  return status === 401
    ? <Navigate to={redirect_path} replace />
    : <Outlet/>;
}

...

const Navbar = () => {
  const { status } = useAuth();
  const is_logged_in= status === 200;

  ...

  return ....;
};

Login/Logout

const Login = ({ type }) => {
  const { setStatus } = useAuth();

  const loginHandler = (....) => {
    ...
    setStatus(200);
  };

  ...

  return ....;
};

const Logout = () => {
  const { setStatus } = useAuth();

  const logoutHandler = (....) => {
    ...
    setStatus(401);
  };

  ...

  return ....;
};

使用依赖于当前位置的 pathname 值的 useEffect 挂钩在路径为 "/".

时发出提取
export default function App() {
  const { pathname } = useLocation();
  const { checkAuthStatus, status } = useAuth();

  useEffect(() => {
    if (pathname === "/") {
      checkAuthStatus();
    }
  }, [pathname]);

  console.log({ status });

  return (
    <div className="App">
      <Navbar />
      <ToastContainer />
      <Routes>
        <Route index element={<Home />} />
        <Route path="/vehicle/:id" element={<EV />} />
        <Route element={<ProtectedRoute />}>
          <Route path="/add" element={<AddEV />} />
        </Route>
        <Route path="/filter" element={<Home />} />
        <Route path="/compare" element={<Home />} />
        <Route path="/login" element={<LoginRegister type="login" />} />
        <Route path="/register" element={<LoginRegister type="register" />} />
        <Route path="/logout" element={<Logout />} />
        <Route path="*" element={<p>Nothing here: 404!</p>} />
      </Routes>
    </div>
  );
}