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
- 引入
withRouter高阶组件,确保AuthLayout能拿到路由相关的props:
import { withRouter } from 'react-router-dom';
- 修改
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> ); }
- 最后用
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
相关产品推荐
相关产品推荐

