React V6类组件登录认证时出现Cannot read properties of undefined (reading 'push')错误求助
解决React Router v6中
Cannot read properties of undefined (reading 'push')错误 这个错误的核心原因是React Router v6彻底移除了对类组件的history props注入,同时useNavigate Hook只能在函数组件中使用,所以你的Login类组件里this.props.history是undefined,调用push自然会报错。下面给你两种可行的解决方案,以及顺便修正你PrivateOutlet里的逻辑问题:
方案一:将Login组件转为函数组件(推荐)
React Router v6更推荐使用函数组件配合Hooks,这样可以直接使用useNavigate:
import React, { useState } from "react"; import Wrapper from "../../../components/Wrapper"; import "./style.css" import logo from "../../../assets/icons/logotipo_semfundo.png" import Button from "@material-ui/core/Button"; import { MdEmail, MdLock } from "react-icons/md" import { useNavigate } from 'react-router-dom'; const Login = () => { const [message, setMessage] = useState(''); const navigate = useNavigate(); let email = ''; let password = ''; const signIn = async event => { const data = { email, password }; const requestInfo = { method: 'POST', body: JSON.stringify(data), headers: new Headers({ 'Content-Type': 'application/json' }), }; try { const response = await fetch('api-link', requestInfo); if (!response.ok) throw new Error('Login Inválido...'); const token = await response.json(); localStorage.setItem('accessToken', token); navigate('/home', { replace: true }); // 直接使用navigate跳转 } catch (e) { setMessage(e.message); } }; return ( <Wrapper className="login"> <Wrapper className="login-img"> <img src={logo} alt="logo" /> </Wrapper> <Wrapper className="login-form"> <h1 className="h1">Login</h1> {message && <span color="black">{message}</span>} <form id="loginForm"> <Wrapper> <Wrapper> <MdEmail /> <input id="email" type="text" name="email" placeholder="Digite um E-mail" onChange={e => email = e.target.value} /> </Wrapper> <Wrapper> <MdLock /> <input id="password" type="password" name="password" placeholder="Senha" onChange={e => password = e.target.value} /> </Wrapper> <Wrapper> <Button onClick={signIn} block="true" color="primary" > Submit </Button> </Wrapper> </Wrapper> </form> </Wrapper> </Wrapper> ); }; export default Login;
方案二:用高阶组件(HOC)给类组件注入navigate
如果你不想改写为函数组件,可以写一个简单的HOC来封装useNavigate,把navigate方法传递给类组件:
1. 创建withNavigate高阶组件
// withNavigate.js import React from 'react'; import { useNavigate } from 'react-router-dom'; export const withNavigate = (Component) => { return (props) => { const navigate = useNavigate(); return <Component {...props} navigate={navigate} />; }; };
2. 修改Login组件的导出
// 导入刚才的HOC import { withNavigate } from './withNavigate'; class Login extends Component { // ... 其他代码保持不变 signIn = async event => { // ... 登录逻辑不变 .then(token => { localStorage.setItem('accessToken', token); // 使用注入的navigate方法跳转 this.props.navigate('/home', { replace: true }); }) .catch(e => this.setState({ message: e.message })); }; } // 用HOC包裹组件后导出 export default withNavigate(Login);
额外修正:PrivateOutlet的认证逻辑错误
你的isAuth函数逻辑写反了:当存在accessToken时应该返回true(表示已认证,可以访问私有路由),但你现在的代码是返回false,会导致已登录用户被跳转到登录页。修正如下:
import React from 'react' import { Navigate, Outlet } from 'react-router-dom' const isAuth = () => { // 存在token则返回true,代表已认证 return localStorage.getItem('accessToken') !== null; } const PrivateOutlet = () => { // 已认证 => 渲染私有页面,否则跳转登录 return isAuth() ? <Outlet /> : <Navigate to="/" state={{ message: 'Usuário não autorizado' }} />; } export default PrivateOutlet
内容的提问来源于stack exchange,提问作者Luca Oliveira
相关产品推荐
相关产品推荐

