在当前版本的React Router (v3)中,我可以接受服务器响应并使用browserHistory。点击进入相应的响应页面。但是,这在v4中是不可用的,我不确定处理它的适当方法是什么。
在这个例子中,使用Redux, components/app-product-form.js在用户提交表单时调用this.props. addproduct (props)。当服务器返回成功时,用户将被带到Cart页面。
// actions/index.js
export function addProduct(props) {
return dispatch =>
axios.post(`${ROOT_URL}/cart`, props, config)
.then(response => {
dispatch({ type: types.AUTH_USER });
localStorage.setItem('token', response.data.token);
browserHistory.push('/cart'); // no longer in React Router V4
});
}
如何从React Router v4的函数重定向到购物车页面?
React Router v4与v3(以及更早的版本)有本质上的不同,你不能像以前那样执行browserHistory.push()。
如果你想了解更多信息,这个讨论似乎是相关的:
创建一个新的browserHistory将不起作用,因为<BrowserRouter>创建了自己的历史实例,并侦听其上的更改。因此,不同的实例将更改url,但不更新<BrowserRouter>。
react-router不会在v4中公开browserHistory,只会在v2中公开。
相反,你有几个选择来做到这一点:
Use the withRouter high-order component
Instead you should use the withRouter high order component, and wrap that to the component that will push to history. For example:
import React from "react";
import { withRouter } from "react-router-dom";
class MyComponent extends React.Component {
...
myFunction() {
this.props.history.push("/some/Path");
}
...
}
export default withRouter(MyComponent);
Check out the official documentation for more info:
You can get access to the history object’s properties and the closest <Route>'s match via the withRouter higher-order component. withRouter will re-render its component every time the route changes with the same props as <Route> render props: { match, location, history }.
Use the context API
Using the context might be one of the easiest solutions, but being an experimental API it is unstable and unsupported. Use it only when everything else fails. Here's an example:
import React from "react";
import PropTypes from "prop-types";
class MyComponent extends React.Component {
static contextTypes = {
router: PropTypes.object
}
constructor(props, context) {
super(props, context);
}
...
myFunction() {
this.context.router.history.push("/some/Path");
}
...
}
Have a look at the official documentation on context:
If you want your application to be stable, don't use context. It is an experimental API and it is likely to break in future releases of React.
If you insist on using context despite these warnings, try to isolate your use of context to a small area and avoid using the context API directly when possible so that it's easier to upgrade when the API changes.
根据React Router v4文档- Redux深度集成会话
深度整合需要:
“能够通过调度操作进行导航”
然而,他们推荐这种方法作为“深度集成”的替代方案:
“你可以将提供给路由组件的历史对象传递给你的操作,而不是分派操作来导航。”
所以你可以用withRouter高阶组件来包装你的组件:
export default withthrouter (connect(null, {actionCreatorName})(ReactComponent));
它将历史API传递给道具。你可以调用动作创建者传递历史作为参数。例如,在你的ReactComponent中:
onClick={() => {
this.props.actionCreatorName(
this.props.history,
otherParams
);
}}
然后,在actions/index.js中:
export function actionCreatorName(history, param) {
return dispatch => {
dispatch({
type: SOME_ACTION,
payload: param.data
});
history.push("/path");
};
}
您可以在组件外部使用历史方法。试试下面的方法。
首先,使用历史包创建一个历史对象:
// src/history.js
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
然后将它包装在<Router>中(请注意,你应该使用import {Router}而不是import {BrowserRouter as Router}):
// src/index.jsx
// ...
import { Router, Route, Link } from 'react-router-dom';
import history from './history';
ReactDOM.render(
<Provider store={store}>
<Router history={history}>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/login">Login</Link></li>
</ul>
<Route exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
</div>
</Router>
</Provider>,
document.getElementById('root'),
);
从任何地方更改当前位置,例如:
// src/actions/userActionCreators.js
// ...
import history from '../history';
export function login(credentials) {
return function (dispatch) {
return loginRemotely(credentials)
.then((response) => {
// ...
history.push('/');
});
};
}
UPD:你也可以在React Router FAQ中看到一个稍微不同的例子。
我再提供一个解决方案,以防它对其他人有用。
我有一个history.js文件,其中我有以下内容:
import createHistory from 'history/createBrowserHistory'
const history = createHistory()
history.pushLater = (...args) => setImmediate(() => history.push(...args))
export default history
接下来,在我定义路由器的根目录上,我使用以下命令:
import history from '../history'
import { Provider } from 'react-redux'
import { Router, Route, Switch } from 'react-router-dom'
export default class Root extends React.Component {
render() {
return (
<Provider store={store}>
<Router history={history}>
<Switch>
...
</Switch>
</Router>
</Provider>
)
}
}
最后,在我的actions.js中,我导入历史并使用pushLater
import history from './history'
export const login = createAction(
...
history.pushLater({ pathname: PATH_REDIRECT_LOGIN })
...)
这样,我可以在API调用之后推送到新的操作。
希望能有所帮助!