You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Router V5:无法从路由向子组件传递state的问题

React Router V5 重定向失效问题

我想要实现一个简单的重定向功能:当用户尝试访问受限URL时,会被重定向到登录页面,登录完成后再返回原本要访问的URL。例如:website.com/settings是受保护页面,未登录时会重定向到登录页,登录后跳转回settings。该功能原本正常工作,但在我最近重新嵌套路由以加入布局后失效了。我推测重定向URL已经传递到父路由,但不确定如何将其传递到子组件。

App.js 路由结构

<Switch>
    <Route path="/password-reset/:reset_key?" exact>
        <AuthLayout>
            <PasswordReset />
        </AuthLayout>
    </Route>
    <Route path="/register" exact>
        <AuthLayout>
            <Register />
        </AuthLayout>
    </Route>
    <Route path="/login" exact>
        <AuthLayout>
            <Login />
        </AuthLayout>
    </Route>
    {/* Other MainLayout routes */}
    <Route>
        <MainLayout>
            <Switch>
                <Route path="/" exact component={Dashboard} />
                <Route path="/search" exact component={SearchResults} />
                <Route path="/user/:user_id" exact component={Profile} />
                <PrivateRoute path="/settings" exact component={Settings} />
                <Route path="/communities" exact component={CommunityDashboard} />
                <PrivateRoute path="/communities/new" exact component={CommunityNew} />
                <Route path="/communities/view/:community_id" exact component={CommunityView} />
                <PrivateRoute path="/communities/edit/:community_id" exact component={CommunityEdit} />
                <Route path='/404' component={Error404} />
            </Switch>
        </MainLayout>
    </Route>
    <Redirect from='*' to='/404' />
</Switch>

PrivateRoute 组件代码

const PrivateRoute = ({component: Component, path, auth, ...rest}) => (
<Route
    {...rest}
    render = {props =>
        auth.isAuthenticated === true ? (
            <Component {...props} />
        ) : (
            <Redirect to={{
                pathname: '/login',
                state: {
                    redirectUrl: window.location.href.includes('login') ? '/' : window.location.href
                }
            }} />
        )
    }
/>
);

AuthLayout 布局组件

import React from 'react';
import './auth.css';
import PropTypes from "prop-types";
import {connect} from "react-redux";

class AuthLayout extends React.Component {

componentDidMount() {
    if(this.props.auth.isAuthenticated){
        this.props.history.push('/');
    }
}

render() {
    return (
        <div className="auth-background">
            <img
                alt=""
                className="logo"
                src={require("./logo1.png")}
            />
            <div id='auth-form'>
                {this.props.children}
            </div>
        </div>
    );
    }
}

AuthLayout.propTypes = {
    auth: PropTypes.object.isRequired
}

const mapStateToProps = (state) => ({
    auth: state.auth
});

export default connect(mapStateToProps, {})(AuthLayout);

LoginForm 登录组件(部分代码)

class LoginForm extends React.Component {
constructor(props){
    super(props);
    this.state = {
        email: '',
        password: '',
        errors: {}
    }
}

handleSubmit = values => {
    const userData = {
        email: values.email,
        password: values.password
    };

    const redirectUrl = this.props.location ? this.props.location.state.redirectUrl : "/"

    this.props.loginUser(userData, redirectUrl, this.props.history);
};

render() {
    return (
        // 登录表单代码
    )
}
}

问题原因与解决方案

问题出在路由嵌套后,Redirect传递的state只到了AuthLayout组件,但AuthLayout没有把路由相关的props(包括location)传递给子组件LoginForm,导致登录组件拿不到redirectUrl。

方案一:修改 AuthLayout 传递路由 props

  1. 引入withRouter高阶组件,确保AuthLayout能拿到路由相关的props:
import { withRouter } from 'react-router-dom';
  1. 修改AuthLayout的render方法,将路由props传递给子组件:
render() {
    return (
        <div className="auth-background">
            <img
                alt=""
                className="logo"
                src={require("./logo1.png")}
            />
            <div id='auth-form'>
                {React.cloneElement(this.props.children, {
                    location: this.props.location,
                    history: this.props.history
                })}
            </div>
        </div>
    );
}
  1. 最后用withRouter包裹导出的组件:
export default withRouter(connect(mapStateToProps, {})(AuthLayout));

方案二:修改 Login 路由的渲染方式

直接在App.js的Login路由中,通过render方法把路由props传递给AuthLayout和Login组件:

<Route path="/login" exact render={(props) => (
    <AuthLayout {...props}>
        <Login {...props} />
    </AuthLayout>
)} />

优化建议

PrivateRoute中用window.location.href获取跳转地址不够可靠,建议改用路由的props.location.pathname,避免域名等无关内容:

const PrivateRoute = ({component: Component, path, auth, ...rest}) => (
<Route
    {...rest}
    render = {props =>
        auth.isAuthenticated === true ? (
            <Component {...props} />
        ) : (
            <Redirect to={{
                pathname: '/login',
                state: {
                    redirectUrl: props.location.pathname
                }
            }} />
        )
    }
/>
);

内容的提问来源于stack exchange,提问作者Sam Munroe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 19:14:52