Col*_*amp 313 ecmascript-6 reactjs react-router-v4
我刚刚react-router
从v3 更换为v4.
但我不知道如何以编程方式导航到一个成员函数Component
.即在handleClick()
功能中我想/path/some/where
在处理一些数据后导航到.我曾经这样做过:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
Run Code Online (Sandbox Code Playgroud)
但我在v4中找不到这样的接口.
如何使用v4导航?
rgo*_*ezz 400
如果您的目标是浏览器环境,则需要使用react-router-dom
package而不是react-router
.它们遵循与React相同的方法,以便将核心,(react
)和平台特定代码(react-dom
,react-native
)与您不需要安装两个独立包的细微差别分开,因此环境包包含所有内容你需要.您可以将其添加到项目中:
yarn add react-router-dom
要么
npm i react-router-dom
您需要做的第一件事是<BrowserRouter>
在应用程序中提供一个最顶级的父组件.<BrowserRouter>
使用HTML5 history
API并为您管理它,因此您不必担心自己实例化它并将其<BrowserRouter>
作为支柱传递给组件(正如您在以前的版本中所需要的那样).
在V4中,为了以编程方式进行导航,只要您将提供程序组件作为应用程序中最顶层的父组件,就需要访问history
可通过React 访问的对象.该库通过上下文公开对象,该对象本身包含作为属性.该接口提供多种导航方法,比如,和,等等.您可以在此处查看属性和方法的完整列表.context
<BrowserRouter>
router
history
history
push
replace
goBack
这种情况正在发生,因为使用上下文模型react-router
传递location
给组件.
connect和observer都创建组件,其shouldComponentUpdate方法对其当前道具及其下一个道具进行浅层比较.只有当至少一个道具发生变化时,这些组件才会重新渲染.这意味着为了确保在位置发生变化时更新,他们需要获得一个在位置发生变化时更改的道具.
解决这个问题的两种方法是:
<Route />
.当前location
对象是<Route>
传递给它呈现的组件的道具之一withRouter
实际上具有相同的效果并location
作为道具 注入除此之外,有四种方式以编程方式导航,按推荐排序:
<Route>
组件<Route />
组件放置在组件层次结构的顶部,必须事先考虑您的路径结构.但是,现在您可以在树中的任何位置放置<Route>
组件,从而可以根据URL对条件渲染进行更精细的控制.注入,并作为组件的道具.导航方法(如,,...)都可以作为属性对象.Route
match
location
history
push
replace
goBack
history
有3种方式来呈现一个东西Route
,通过使用component
,render
或children
道具,但不要使用超过一个在同一个Route
.选择取决于用例,但基本上前两个选项仅在path
匹配url位置时呈现组件,而children
组件将呈现路径是否与位置匹配(对于基于URL调整UI有用)匹配).
如果您想自定义您的组件渲染输出,你需要用你的组件在功能和使用render
选项,以便传递给您的组件,你的愿望,除了任何其他的道具match
,location
和history
.举例说明:
import { BrowserRouter as Router } from 'react-router-dom'
const ButtonToNavigate = ({ title, history }) => (
<button
type="button"
onClick={() => history.push('/my-new-location')}
>
{title}
</button>
);
const SomeComponent = () => (
<Route path="/" render={(props) => <ButtonToNavigate {...props} title="Navigate elsewhere" />} />
)
const App = () => (
<Router>
<SomeComponent /> // Notice how in v4 we can have any other component interleaved
<AnotherComponent />
</Router>
);
Run Code Online (Sandbox Code Playgroud)
withRouter
HoC这个更高阶的组件将注入相同的道具Route
.但是,它带有每个文件只能有1个HoC的限制.
import { withRouter } from 'react-router-dom'
const ButtonToNavigate = ({ history }) => (
<button
type="button"
onClick={() => history.push('/my-new-location')}
>
Navigate
</button>
);
ButtonToNavigate.propTypes = {
history: React.PropTypes.shape({
push: React.PropTypes.func.isRequired,
}),
};
export default withRouter(ButtonToNavigate);
Run Code Online (Sandbox Code Playgroud)
Redirect
组件<Redirect>
将导航到新位置.但请记住,默认情况下,当前位置将替换为新位置,如服务器端重定向(HTTP 3xx).新位置由to
prop 提供,可以是字符串(重定向到的URL)或location
对象.如果您想要将新条目推送到历史记录中,请传递push
道具并将其设置为true
<Redirect to="/your-new-location" push />
Run Code Online (Sandbox Code Playgroud)
router
通过上下文手动访问const ButtonToNavigate = (props, context) => (
<button
type="button"
onClick={() => context.router.history.push('/my-new-location')}
>
Navigate to a new location
</button>
);
ButtonToNavigate.contextTypes = {
router: React.PropTypes.shape({
history: React.PropTypes.object.isRequired,
}),
};
Run Code Online (Sandbox Code Playgroud)
毋庸置疑,还有其他路由器组件适用于非浏览器生态系统,例如在内存<NativeRouter>
中复制导航堆栈并以React Native平台为目标,可通过包获得.react-router-native
如有任何进一步的参考,请不要犹豫,看看官方文档.还有一个由该库的共同作者制作的视频,它为react-router v4提供了很酷的介绍,突出了一些重大变化.
Jik*_*ose 143
完成任务的最简单方法:
this.props.history.push("/new/url")
注意:
history
prop
如果不可用,您可能希望将父组件向下传递给要调用操作的组件.Ale*_*ann 55
迁移到React-Router v4时我遇到了类似的问题,所以我将尝试解释下面的解决方案.
请不要将这个答案视为解决问题的正确方法,我想有一个很好的机会会出现更好的事情,因为React Router v4变得更加成熟并且离开了beta(它甚至可能已经存在,我只是没有发现它) .
对于上下文,我遇到了这个问题,因为我偶尔会Redux-Saga
以编程方式更改历史记录对象(例如,当用户成功进行身份验证时).
在React Router文档中,查看<Router>
组件,您可以看到您能够通过prop传递自己的历史对象.这是该方案的本质- 我们提供的历史对象,以React-Router
从全球模块.
yarn add history
或 npm install history --save
创建一个history.js
在App.js
level文件夹中调用的文件(这是我的偏好)
// src/history.js
import createHistory from 'history/createBrowserHistory';
export default createHistory();`
Run Code Online (Sandbox Code Playgroud)将此历史记录对象添加到您的路由器组件中
// src/App.js
import history from '../your/path/to/history.js;'
<Router history={history}>
// Route tags here
</Router>
Run Code Online (Sandbox Code Playgroud)通过导入调整URL就像之前你的世界历史的对象:
import history from '../your/path/to/history.js;'
history.push('new/path/here/');
Run Code Online (Sandbox Code Playgroud)现在一切都应该保持同步,并且您还可以访问以编程方式而不是通过组件/容器设置历史对象的方法.
Lyu*_*mir 39
TL; DR:
if (navigate) {
return <Redirect to="/" push={true} />
}
Run Code Online (Sandbox Code Playgroud)
简单而陈述的答案是你需要<Redirect to={URL} push={boolean} />
结合使用setState()
push:boolean -当为true时,重定向将把新条目推送到历史记录而不是替换当前的条目.
import { Redirect } from 'react-router'
class FooBar extends React.Component {
state = {
navigate: false
}
render() {
const { navigate } = this.state
// here is the important part
if (navigate) {
return <Redirect to="/" push={true} />
}
// ^^^^^^^^^^^^^^^^^^^^^^^
return (
<div>
<button onClick={() => this.setState({ navigate: true })}>
Home
</button>
</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
PS.该示例使用ES7 +属性初始化程序初始化状态.如果你有兴趣,也可以看看这里.
Mis*_*rov 36
useHistory
如果您使用函数组件,请使用钩子您可以使用useHistory
钩子来获取history
实例。
import { useHistory } from "react-router-dom";
const MyComponent = () => {
const history = useHistory();
return (
<button onClick={() => history.push("/about")}>
Click me
</button>
);
}
Run Code Online (Sandbox Code Playgroud)
该useHistory
挂钩使您可以访问可用于导航的历史记录实例。
history
在页面组件内使用属性React Router 注入了一些属性,包括history
页面组件。
class HomePage extends React.Component {
render() {
const { history } = this.props;
return (
<div>
<button onClick={() => history.push("/projects")}>
Projects
</button>
</div>
);
}
}
Run Code Online (Sandbox Code Playgroud)
withRouter
以注入路由器属性withRouter
包装器将路由器属性注入组件。例如,您可以使用此包装器将路由器注入用户菜单中的注销按钮组件。
import { withRouter } from "react-router";
const LogoutButton = withRouter(({ history }) => {
return (
<button onClick={() => history.push("/login")}>
Logout
</button>
);
});
export default LogoutButton;
Run Code Online (Sandbox Code Playgroud)
也可以简单地使用道具: this.props.history.push('new_url')
小智 8
第1步:在顶部只导入一件事:
import {Route} from 'react-router-dom';
Run Code Online (Sandbox Code Playgroud)
第2步:在你的路线中,传递历史:
<Route exact path='/posts/add' render={({history}) => (
<PostAdd
history={history}
/>
.)}/>
Run Code Online (Sandbox Code Playgroud)
第3步:历史记录在下一个组件中被接受为道具的一部分,因此您可以简单地:
this.props.history.push('/');
Run Code Online (Sandbox Code Playgroud)
这很容易而且非常强大.
这有效:
import { withRouter } from 'react-router-dom';
const SomeComponent = withRouter(({ history }) => (
<div onClick={() => history.push('/path/some/where')}>
some clickable element
</div>);
);
export default SomeComponent;
Run Code Online (Sandbox Code Playgroud)
小智 7
您可以通过这种方式有条件地导航
import { useHistory } from "react-router-dom";
function HomeButton() {
const history = useHistory();
function handleClick() {
history.push("/path/some/where");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
Run Code Online (Sandbox Code Playgroud)
我已经测试 v4 几天了......到目前为止我很喜欢它!一段时间后才有意义。
我也有同样的问题,我发现像下面这样处理它效果最好(甚至可能是它的意图)。它使用状态、三元运算符和<Redirect>
。
在构造函数()中
this.state = {
redirectTo: null
}
this.clickhandler = this.clickhandler.bind(this);
Run Code Online (Sandbox Code Playgroud)
在渲染()中
render(){
return (
<div>
{ this.state.redirectTo ?
<Redirect to={{ pathname: this.state.redirectTo }} /> :
(
<div>
..
<button onClick={ this.clickhandler } />
..
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
在点击处理程序()中
this.setState({ redirectTo: '/path/some/where' });
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你。让我知道。
我的答案与Alex的相似.我不确定为什么React-Router这样做不必要地复杂化.为什么我必须用HoC包装我的组件才能访问本质上是全局的?
无论如何,如果你看看它们是如何实现的<BrowserRouter>
,它只是历史的一个小包装.
我们可以将该历史记录拉出来,以便我们可以从任何地方导入它.但是,诀窍在于,如果您正在进行服务器端渲染并尝试import
使用历史记录模块,那么它将无法工作,因为它使用仅浏览器的API.但这没关系,因为我们通常只会重定向以响应点击或其他一些客户端事件.因此伪造它可能是可以的:
// history.js
if(__SERVER__) {
module.exports = {};
} else {
module.exports = require('history').createBrowserHistory();
}
Run Code Online (Sandbox Code Playgroud)
在webpack的帮助下,我们可以定义一些变量,以便我们知道我们所处的环境:
plugins: [
new DefinePlugin({
'__SERVER__': 'false',
'__BROWSER__': 'true', // you really only need one of these, but I like to have both
}),
Run Code Online (Sandbox Code Playgroud)
现在你可以
import history from './history';
Run Code Online (Sandbox Code Playgroud)
从任何地方.它只会在服务器上返回一个空模块.
如果你不想使用这些魔法变量,你只需要require
在需要它的全局对象中(在你的事件处理程序中).import
不起作用,因为它只适用于顶层.
我为此苦苦挣扎了一段时间——事情如此简单,但又如此复杂,因为 ReactJS 只是一种完全不同的编写 Web 应用程序的方式,它对我们老年人来说非常陌生!
我创建了一个单独的组件来消除混乱:
// LinkButton.js
import React from "react";
import PropTypes from "prop-types";
import {Route} from 'react-router-dom';
export default class LinkButton extends React.Component {
render() {
return (
<Route render={({history}) => (
<button {...this.props}
onClick={() => {
history.push(this.props.to)
}}>
{this.props.children}
</button>
)}/>
);
}
}
LinkButton.propTypes = {
to: PropTypes.string.isRequired
};
Run Code Online (Sandbox Code Playgroud)
然后将其添加到您的render()
方法中:
<LinkButton className="btn btn-primary" to="/location">
Button Text
</LinkButton>
Run Code Online (Sandbox Code Playgroud)
我认为@rgommezz涵盖了大多数情况,但我认为这很重要。
// history is already a dependency or React Router, but if don't have it then try npm install save-dev history
import createHistory from "history/createBrowserHistory"
// in your function then call add the below
const history = createHistory();
// Use push, replace, and go to navigate around.
history.push("/home");
Run Code Online (Sandbox Code Playgroud)
这使我可以编写带有操作/调用的简单服务,可以调用该操作/调用以从所需的任何组件进行导航,而无需在组件上进行大量的HoC工作...
尚不清楚为什么以前没有人提供此解决方案。希望对您有所帮助,如果您发现任何问题,请告诉我。
归档时间: |
|
查看次数: |
218489 次 |
最近记录: |