简体   繁体   English

为什么在使用 React Router V6 保护路由时,我使用 AWS Amplify 的 React Authentication 组件会被无限渲染

[英]Why is my React Authentication component using AWS Amplify being rendered infinitely when using React Router V6 to protect routes

I am trying to create my own custom authentication using React, AWS Amplify, and React Router V6, and my goal is to protect certain routes so users that are not logged in can't access them.我正在尝试使用 React、AWS Amplify 和 React Router V6 创建我自己的自定义身份验证,我的目标是保护某些路由,以便未登录的用户无法访问它们。

My code is here:我的代码在这里:

import './App.css';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Navbar from './components/Navbar/Navbar';
import Dashboard from './components/Dashboard/Dashboard';
import Reports from './components/Reports/Reports';
import Patients from './components/Patients/Patients';
import { BrowserRouter, Navigate, Outlet, Route, Routes, useLocation, } from 'react-router-dom';
import React, { useEffect, useState } from 'react';
import '@aws-amplify/ui-react/styles.css';
import Signup from './components/Signup/Signup';
import Signin from './components/Signin/Signin';
import { Auth } from 'aws-amplify';

const darkTheme = createTheme({
  palette: {
    mode: 'dark',
  }
});

const useAuth = () => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const fetchUser = async () => {
      const response = await Auth.currentAuthenticatedUser();
      setUser(response);
    }
    fetchUser();
  })

  return { user };
}

function RequireAuth() {
  const auth = useAuth();
  const location = useLocation();
  console.log(auth);

  return (
    auth
      ? <Outlet/>
      : <Navigate to='/signin' state={{ from: location}} replace/>
  );
}

const App = () => {

  return (
    <ThemeProvider theme={darkTheme}>
      <BrowserRouter>
        <Routes>
          <Route element={<RequireAuth />}>
            <Route path="/" element={<Navbar />}>
              <Route path="dashboard" element={<Dashboard />} />
              <Route path="patients" element={<Patients />} />
              <Route path="reports" element={<Reports />} />
            </Route>
          </Route>
          <Route path="/signin" element={<Signin />} />
          <Route path="/signup" element={<Signup />} />
        </Routes>
      </BrowserRouter>
    </ThemeProvider>
  );
}

export default App;

I have spent the whole day trying countless methods but I keep getting the same results.我花了一整天的时间尝试了无数种方法,但我一直得到相同的结果。 What I'm trying to do is protect 3 routes Dashboard, Patients, and Reports.我想做的是保护 3 条路线仪表板、患者和报告。 Whenever I click the sign-in button, I get around 500 logs of the current user as shown below:每当我单击登录按钮时,我都会得到当前用户的大约 500 条日志,如下所示:

在此处输入图像描述

Does anyone know what is triggering this component to re-render infinitely (hence executing my console.log(user) function), and is there any solution to fix this?有谁知道是什么触发了这个组件无限地重新渲染(因此执行了我的 console.log(user) 函数),有什么解决方案可以解决这个问题吗?

It appears the useEffect hook is missing a dependency array, so its callback is triggered each render cycle. useEffect挂钩似乎缺少依赖项数组,因此每个渲染周期都会触发其回调。 Since the effect updates state, it triggers a rerender.由于效果更新 state,它会触发重新渲染。

Add a dependency array.添加一个依赖数组。

useEffect(() => {
  const fetchUser = async () => {
    const response = await Auth.currentAuthenticatedUser();
    setUser(response);
  }
  fetchUser();
}, []);

If you need to run this effect more than once when the routes are mounted, then you may need to add a dependency, like location if/when the route path changes.如果您需要在安装路由时多次运行此效果,那么您可能需要添加依赖项,例如location if/when 路由路径更改。

Example:例子:

const { pathname } = useLocation();

useEffect(() => {
  const fetchUser = async () => {
    const response = await Auth.currentAuthenticatedUser();
    setUser(response);
  }
  fetchUser();
}, [pathname]);

Since the useEffect hook runs at the end of the initial render cycle you may want to also conditionally wait to render the outlet or redirect until the user state is populated.由于useEffect挂钩在初始渲染周期结束时运行,您可能还希望有条件地等待渲染插座或重定向,直到user state 被填充。

Example:例子:

const useAuth = () => {
  const [user, setUser] = useState(); // <-- initially undefined

  useEffect(() => {
    const fetchUser = async () => {
      const response = await Auth.currentAuthenticatedUser();
      setUser(response);
    }
    fetchUser();
  }, []);

  return { user };
}

... ...

function RequireAuth() {
  const auth = useAuth();
  const location = useLocation();

  if (auth === undefined) {
    return null; // or loading indicator, etc...
  }

  return (
    auth
      ? <Outlet/>
      : <Navigate to='/signin' state={{ from: location }} replace/>
  );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM