如何在 React Router v4 中操作历史记录?
How to manipulate history in React Router v4?
我正在使用:
React、Redux、React-Router、Meteor
以下情况:
我有一个带有两个选项卡的模式,根据所选选项卡,内容区域中将显示不同的选择列表,选择一个选择将给出子选择列表(全部在模式内)。
期望的行为:
我希望用户能够使用浏览器的后退按钮 "undo" 单击其中一个选项卡或进行选择。
到目前为止我试过什么都没有成功:
使用 withRouter HOC 包装我的组件,这样我就可以访问历史记录。然后我会使用 history.push(currentUrl,{selectedTab:selection})
-> 问题:推送的状态没有存储在这个历史位置对象上,而是只存储在与我的根组件关联的历史对象的状态中(在树的更上层)
(到目前为止更有希望)只需将我用 createHistory 创建的历史导入另一个模块,然后将其放入构建时的组件状态。
然后我会使用 this.state.history.push(currentUrl,{selectedTab:selection})
访问 push 方法,它工作正常,我可以在 this.state.history.location.state.selectedTab
下找到推送状态。但是,使用浏览器的后退按钮不会导致重新呈现,因此选择将保持不变。
有什么想法吗?
干杯
我改进了第二种方法,现在可以使用了。将历史导入我的模块(作为局部变量)并因此完全绕过 React 树、redux 存储和 React 路由器仍然感觉很笨拙。
但是,它正在运行并且到目前为止没有引起任何错误。那么我们开始吧...
我实例化了我的历史对象:
store.js 模块:
import createHistory from 'history/createBrowserHistory';
...
const history = createHistory();
...
export { history , store }
如您所见,导出历史记录。然后我将所述历史记录提供给我的路由器(在我的例子中是 ConnectedRouter,因为我使用的是 react-router-redux):
routes.js module
import { store , history } from '/imports/client/store';
const MyStoreRouter = () => {
return (
<Provider store={store}>
<ConnectedRouter history={ history }>
<div>
<Switch>
<Route exact path="/" component={Landing}/>
<Route path="/" component={MainApp}/>
</Switch>
</div>
</ConnectedRouter>
</Provider>
);
};
现在是古怪的部分。我将历史导入显示组件并使用它来设置侦听器(在 history.location 中声明更改)并相应地更改状态:
DisplayComponent.js模块:
import { history } from '/imports/client/store';
....
export default class EventCreationModal extends Component {
constructor() {
super();
this.handleSelect = this.handleSelect.bind(this);
this.state = {
selectedCategory: (history.location.state && history.location.state.category) ? history.location.state.category : 'sports',
};
history.listen((location,action) => {
this.setState({
selectedCategory: (history.location.state && history.location.state.category) ? history.location.state.category : 'sports',
})
});
}
handleSelect(key) {
history.push("/Home",{'category':key})
}
render () {
return (
<Tabs activeKey={this.state.selectedCategory} onSelect={this.handleSelect} id="SportOrSocialSelector">
<Tab eventKey={'sports} .../>
<Tab eventKey={'social} .../>
</Tabs>
)
}
您可以采用的另一种方法是将查询参数与 React 路由器一起使用。并在您的组件中根据查询参数更改选项卡。由于 url 发生了变化,您应该会得到您想要的默认行为。
我有一个项目几乎就是这种情况。不同之处在于,它不是在模态中,而是在我的 header 中。这是我所做的:
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
class Header extends Component {
render() {
return (
<ul className="tabs tabs-fixed-width z-depth-1">
<li className="tab">
<Link id="books-tab" to={'/books'}>Books</Link>
</li>
<li className="tab">
<Link id="stats-tab" to={'/stats'}>Stats</Link>
</li>
{Meteor.userId() &&
<li className="tab">
<Link id="user-tab" to={'/user'}>Account Settings</Link>
</li>}
</ul>
);
}
}
export default withRouter(Header);
react-router-dom <Link>...
是允许这种情况发生的有效项目。
然后,当我单击选项卡时,每个 link 都会转到指定的 url 并将其保留在历史记录中,这样我就可以返回并返回到上一个选项卡。
我正在使用:
React、Redux、React-Router、Meteor
以下情况:
我有一个带有两个选项卡的模式,根据所选选项卡,内容区域中将显示不同的选择列表,选择一个选择将给出子选择列表(全部在模式内)。
期望的行为:
我希望用户能够使用浏览器的后退按钮 "undo" 单击其中一个选项卡或进行选择。
到目前为止我试过什么都没有成功:
使用 withRouter HOC 包装我的组件,这样我就可以访问历史记录。然后我会使用 history.push(currentUrl,{selectedTab:selection}) -> 问题:推送的状态没有存储在这个历史位置对象上,而是只存储在与我的根组件关联的历史对象的状态中(在树的更上层)
(到目前为止更有希望)只需将我用 createHistory 创建的历史导入另一个模块,然后将其放入构建时的组件状态。 然后我会使用
this.state.history.push(currentUrl,{selectedTab:selection})
访问 push 方法,它工作正常,我可以在this.state.history.location.state.selectedTab
下找到推送状态。但是,使用浏览器的后退按钮不会导致重新呈现,因此选择将保持不变。
有什么想法吗?
干杯
我改进了第二种方法,现在可以使用了。将历史导入我的模块(作为局部变量)并因此完全绕过 React 树、redux 存储和 React 路由器仍然感觉很笨拙。 但是,它正在运行并且到目前为止没有引起任何错误。那么我们开始吧...
我实例化了我的历史对象:
store.js 模块:
import createHistory from 'history/createBrowserHistory';
...
const history = createHistory();
...
export { history , store }
如您所见,导出历史记录。然后我将所述历史记录提供给我的路由器(在我的例子中是 ConnectedRouter,因为我使用的是 react-router-redux):
routes.js module
import { store , history } from '/imports/client/store';
const MyStoreRouter = () => {
return (
<Provider store={store}>
<ConnectedRouter history={ history }>
<div>
<Switch>
<Route exact path="/" component={Landing}/>
<Route path="/" component={MainApp}/>
</Switch>
</div>
</ConnectedRouter>
</Provider>
);
};
现在是古怪的部分。我将历史导入显示组件并使用它来设置侦听器(在 history.location 中声明更改)并相应地更改状态:
DisplayComponent.js模块:
import { history } from '/imports/client/store';
....
export default class EventCreationModal extends Component {
constructor() {
super();
this.handleSelect = this.handleSelect.bind(this);
this.state = {
selectedCategory: (history.location.state && history.location.state.category) ? history.location.state.category : 'sports',
};
history.listen((location,action) => {
this.setState({
selectedCategory: (history.location.state && history.location.state.category) ? history.location.state.category : 'sports',
})
});
}
handleSelect(key) {
history.push("/Home",{'category':key})
}
render () {
return (
<Tabs activeKey={this.state.selectedCategory} onSelect={this.handleSelect} id="SportOrSocialSelector">
<Tab eventKey={'sports} .../>
<Tab eventKey={'social} .../>
</Tabs>
)
}
您可以采用的另一种方法是将查询参数与 React 路由器一起使用。并在您的组件中根据查询参数更改选项卡。由于 url 发生了变化,您应该会得到您想要的默认行为。
我有一个项目几乎就是这种情况。不同之处在于,它不是在模态中,而是在我的 header 中。这是我所做的:
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
class Header extends Component {
render() {
return (
<ul className="tabs tabs-fixed-width z-depth-1">
<li className="tab">
<Link id="books-tab" to={'/books'}>Books</Link>
</li>
<li className="tab">
<Link id="stats-tab" to={'/stats'}>Stats</Link>
</li>
{Meteor.userId() &&
<li className="tab">
<Link id="user-tab" to={'/user'}>Account Settings</Link>
</li>}
</ul>
);
}
}
export default withRouter(Header);
react-router-dom <Link>...
是允许这种情况发生的有效项目。
然后,当我单击选项卡时,每个 link 都会转到指定的 url 并将其保留在历史记录中,这样我就可以返回并返回到上一个选项卡。