react-router-dom是否含browserHistory?如何用history.push跳转页面
React Router DOM 实现页面跳转指南(针对你的代码)
嘿,我来帮你理清这些问题,一步步解决登录后跳转的需求:
核心问题解答
- react-router-dom 里还有 browserHistory 吗?
没有啦!从 react-router-dom v4 开始,browserHistory就被移除了,不再直接对外暴露。现在我们是通过路由上下文传递的history对象来实现跳转,这个对象有push方法可以用。 - react-router-dom 本身有 push 属性吗?
不是库本身带,而是路由给组件传递的props.history对象拥有push方法,我们就是靠它来跳转页面的。
具体修改步骤
先确认你已经安装了 react-router-dom(不需要额外装 react-router,它已经包含在前者里了),如果没装,执行:
npm install react-router-dom # 或者用 yarn yarn add react-router-dom
1. 先修正 Routes.js 的 Router 类型
你当前用的 Router 需要换成 BrowserRouter(这是实现browser history模式的正确组件),修改后的代码:
// 导入正确的组件 import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; // 记得替换成你实际的组件路径 import HomePage from './HomePage'; import About from './About'; import LoginForm from './LoginForm'; import Companies from './Companies'; import Services from './Services'; import Contact from './Contact'; import UserPage from './UserPage'; class Routes extends Component { render() { return ( <div> <Router> <Switch> <Route exact path="/" component={HomePage}/> <Route path="/about" component={About}/> <Route path="/loginform" component={LoginForm}/> <Route path="/companies" component={Companies}/> <Route path="/services" component={Services}/> <Route path="/contact" component={Contact}/> <Route path="/userpage" component={UserPage}/> </Switch> </Router> </div> ); } } export default Routes;
2. 方案一:在 LoginForm 中监听登录状态跳转(最直接)
因为你的登录状态存在Redux里,我们可以在LoginForm组件中监听isLoginSuccess的变化,一旦登录成功就触发跳转:
修改 LoginForm.js:
// 导入 withRouter 高阶组件,用来获取 history props import { withRouter } from 'react-router-dom'; class LoginForm extends Component { constructor(props) { super(props); this.state = {}; this.onSubmit = this.onSubmit.bind(this); } // 监听props变化,当登录成功状态从false变true时跳转 componentDidUpdate(prevProps) { if (!prevProps.isLoginSuccess && this.props.isLoginSuccess) { this.props.history.push('/userpage'); } } render() { let {username, password} = this.state; let {isLoginPending, isLoginSuccess, loginError} = this.props; return ( <div> <Back/> <header> <h1>Company Login</h1> </header> <form name="loginForm" onSubmit={this.onSubmit}> <div className="imgcontainer"> <img src={avatar} alt={"Avatar"} className={"avatar"}/> </div> <div className="form-group-collection"> <div className="form-group"> <label>Username/User ID:</label> <input name="username" onChange={e => this.setState({username: e.target.value})} value={username}/> </div> <div className="form-group"> <label>Password:</label> <input type="password" name="password" onChange={e => this.setState({password: e.target.value})} value={password}/> </div> </div> <br/> <input type="submit" value="Login" /> </form> <footer>Copyright © multihands.com. </footer> </div> ) } onSubmit(e) { e.preventDefault(); let { username, password } = this.state; this.props.login(username, password); this.setState({ username: '', password: '' }); } } const mapStateToProps = (state) => { return { isLoginPending: state.isLoginPending, isLoginSuccess: state.isLoginSuccess, loginError: state.loginError }; } const mapDispatchToProps = (dispatch) => { return { login: (username, password) => dispatch(login(username, password)) }; } // 用withRouter包裹connect后的组件,这样就能拿到history props export default withRouter(connect(mapStateToProps, mapDispatchToProps)(LoginForm));
3. 方案二:在Redux Action中直接跳转(适合逻辑集中管理)
如果你想把跳转逻辑和登录成功的逻辑放在一起,可以把history对象传到action里:
首先修改LoginForm的mapDispatchToProps:
const mapDispatchToProps = (dispatch, ownProps) => { return { login: (username, password) => dispatch(login(username, password, ownProps.history)) }; }
然后修改Reducer.js里的login action和callLoginApi:
export function login(username, password, history) { return dispatch => { dispatch(setLoginPending(true)); dispatch(setLoginSuccess(false)); dispatch(setLoginError(null)); callLoginApi(username, password, (error) => { dispatch(setLoginPending(false)); if (!error) { dispatch(setLoginSuccess(true)); // 登录成功后直接跳转 history.push('/userpage'); } else { dispatch(setLoginError(error)); } }); } } function callLoginApi(username, password, callback) { setTimeout(() => { if (username === logindetls.username && password === logindetls.password) { alert("Successfully Logged in..."); callback(null); // 无错误时传null } else { alert('Invalid username and password'); callback(new Error('Invalid credentials')); // 有错误时传Error对象 } }, 1000); }
小提醒
- 如果你的组件不是直接被Route渲染的(比如嵌套在其他组件里),一定要用
withRouter包裹才能拿到history props。 - 要是以后改成函数组件,直接用
useHistory钩子就行:const history = useHistory();然后调用history.push('/userpage')。
内容的提问来源于stack exchange,提问作者Sarah
相关产品推荐
相关产品推荐

