我正在制作一个网站,在用户登录后,用户将被重定向到主页.主页和网站的所有其他页面只能由登录用户访问,但即使用户登录(firebase auth)后,网站的其他部分(受保护的路由)仍然无法访问,唯一可访问的页面是登录页面.我使用的技术是react、react路由dom和firebase,这就是我的代码,从应用开始.js

import Home from "./pages/home/Home";
import Login from "./pages/login/Login";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
import List from "./pages/list/List";
import User from "./pages/user/User";
import AddNew from "./pages/addnew/AddNew";
import { useContext } from "react";
import { AuthContext } from "./context/AuthContext";

function App() {
  const {currentUser} = useContext(AuthContext);
  
  const RequireAuth = ({ children }) => {
    return currentUser ? children : <Navigate to="/login" />;
  };


  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path="/login" exact element={<Login />} />
          <Route path="/" exact element={ <RequireAuth> <Home /> </RequireAuth> } />
          <Route path="/users" exact element={<RequireAuth><List /></RequireAuth>} />
          <Route path="/users/:id" exact element={<RequireAuth><User /></RequireAuth>} />
          <Route path="/add" exact element={<RequireAuth><AddNew /></RequireAuth>} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

然后是登录.js页面

import React,{useState} from 'react'
import { useContext } from 'react';
import { signInWithEmailAndPassword } from "firebase/auth";
import { auth } from '../../firebase';
import "./login.css";
import {useNavigate} from "react-router-dom";
import { AuthContext } from '../../context/AuthContext';

export default function Login() {
  const [error, seterror] = useState(false);
  const [email, setemail] = useState("");
  const [password, setpassword] = useState("");
  const navigate = useNavigate();
  const {dispatch} = useContext(AuthContext)
  
  const handleLogin = (e) => {
    e.preventDefault();

    signInWithEmailAndPassword(auth, email, password)
      .then((userCredential) => {
        const user = userCredential.user;
        dispatch({type: "LOGIN", payload: user});
        navigate("/");
      })
      .catch((error) => {
        seterror(true);
        console.log(error.message);
      });
  }


  return (
    <div className='login'>
        <form onSubmit={handleLogin}>
          <input className='ok' type="email" placeholder='email' onChange={e => setemail(e.target.value)} />
          <input className='ok' type="password" placeholder='password' onChange={e => setpassword(e.target.value)} />
          <button className='sb'>Submit</button>
          {error && <span className='ks'>Wrong email or password</span>}
        </form>
    </div>
  )
}

然后我就有了答案.处理状态的js文件

const AuthReducer = (state, action) => {
    switch (action.type) {
        case "LOGIN": {
            return {
                currentUser: action.payload,
            }
        }
        case "LOGOUT": {
            return {
                currentUser: null
            }
        }
        default:
            return state;
    }
}

export default AuthReducer

最后是作者的背景.js文件

import { createContext, useEffect, useReducer } from "react";
import AuthReducer from "./AuthReducer";

const INITIAL_STATE = {
    currentUser: JSON.parse(localStorage.getItem("user")) || null,
}

export const AuthContext = createContext(INITIAL_STATE);

export const AuthContextProvider = ({children}) => {
    const [state, dispatch] = useReducer(AuthReducer, INITIAL_STATE);

    useEffect(() => {
        localStorage.setItem("user", JSON.stringify(state.currentUser))
    }, [state.currentUser])

    return (
        <AuthContext.Provider value={{current: state.current, dispatch}}>
            {children}
        </AuthContext.Provider>
    )
}

我不知道是什么导致了这个问题,但我有一个 idea ,它与国家有关,因为在我开始将它与国家结合之前,它就已经重定向了.有什么问题吗

推荐答案

Issue

从这一点我可以看出,App没有分解正确的上下文值来处理条件路由保护.

AuthContextProvider提供了一个包含currentdispatch个属性的上下文值

<AuthContext.Provider value={{ current: state.current, dispatch }}>
  {children}
</AuthContext.Provider>

但是App正在访问currentUser属性,这将是未定义的,因为state.current是未定义的.

const { currentUser } = useContext(AuthContext);

const RequireAuth = ({ children }) => {
  return currentUser ? children : <Navigate to="/login" />;
};

Navigate组件将始终被渲染.

Solution

假设handleLogin处理程序正确更新状态,那么解决方案将与状态属性一致.

<AuthContext.Provider value={{ currentUser: state.currentUser, dispatch }}>
  {children}
</AuthContext.Provider>

...

const { currentUser } = useContext(AuthContext);

const RequireAuth = ({ children }) => {
  return currentUser ? children : <Navigate to="/login" />;
};

Reactjs相关问答推荐

如何使用React Router创建响应式主详细信息应用程序?

如何避免react 使用ESLINTreact 挂钩/穷举-deps进行第一次呈现

在一个blog函数中调用setState钩子

React-chartjs-2:红色和绿色之间的差距

更新对象状态的父数组时记住子组件

React-router动态路径

我可以同时使用 Gatsby 和 NEXT.JS 吗?

是的验证:使用 useFieldArray 访问表单值

显示我是否加入聊天应用程序时出现问题

下一个js如何从另一个组件更新组件?

臭名昭著的测试未包含在 act(...) 中

Material UI v5.11 - Prop sx 在响应式中写了两次

使用 React Router v6 监听来自不同组件的组件状态变化

如何在 nextjs 中单击按钮时动态导入和渲染组件?

自动重新获取不起作用 - RTK 查询

父状态改变后子组件丢失状态

为什么此代码中的 useState 不更新(文本更新但 id 不更新)?

从输入中获取数字时,react 计数器不会增加

无法重用我的组件,它只显示 1 次

可以'读取未定义的属性(读取'路径')