我刚刚从 v3 替换了react-router
到 v4。
但我不知道如何以编程方式导航Component
的成员函数。 i.e in handleClick()
function 我想在处理一些数据后导航到/path/some/where
。我曾经这样做过:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
但我在 v4 中找不到这样的接口。
如何使用 v4 导航?
14 回答
如果您要定位浏览器环境,则需要使用
react-router-dom
包,而不是react-router
。他们遵循与 React 相同的方法,以便将核心(react
)和平台特定代码(react-dom
,react-native
)与您不需要安装两个独立包的细微差别分开,因此环境包中包含您需要的一切。您可以将其添加到项目中:yarn add react-router-dom
要么
npm i react-router-dom
您需要做的第一件事是提供
<BrowserRouter>
作为应用程序中最顶层的父组件。<BrowserRouter>
使用 HTML5history
API 并为您管理它,因此您不必担心自己实例化它并将其作为道具传递给<BrowserRouter>
组件(正如您在以前版本中所需要的那样)。在 V4 中,为了以编程方式进行导航,只要有一个
<BrowserRouter>
提供程序组件作为应用程序中最顶层的父组件,就需要访问history
对象,该对象可通过 Reactcontext
获得。该库通过上下文公开router
对象,它本身包含history
作为属性。history
接口提供了几种导航方法,例如push
,replace
和goBack
等。您可以检查属性和方法这里的完整列表。Redux/Mobx 用户的重要说明
如果您在应用程序中使用 redux 或 mobx 作为状态管理库,则可能遇到了在触发 URL 更新后应该 location-aware 但不是 re-rendered 的组件的问题
发生这种情况是因为
react-router
使用上下文模型将location
传递给组件。解决这个问题的两种方法是:
将您连接的组件包裹在无路径的
<Route />
中。当前location
对象是<Route>
传递给它呈现的组件的道具之一用
withRouter
higher-order 组件包裹你连接的组件,实际上具有相同的效果并注入location
作为道具除此之外,有四种方式以编程方式导航,按推荐排序:
1.-使用<Route>组件
它促进了一种陈述式的风格。在 v4 之前,
<Route />
组件放置在组件层次结构的顶部,必须事先考虑您的路径结构。但是,现在您可以在树中的任何位置使用<Route>
组件**,从而可以根据 URL 对条件渲染进行更精细的控制。Route
将match
,location
和history
作为道具注入到组件中。导航方法(例如push
,replace
,goBack
...)可用作history
对象的属性。通过使用
component
,render
或children
道具,有 3 种方法可以使用Route
渲染某些内容,但不要在同一个Route
中使用多个。选择取决于用例,但基本上前两个选项只会在path
匹配 url 位置时呈现组件,而使用children
将呈现组件,无论路径是否与位置匹配(对于调整基于 UI 的用途)在 URL 匹配上)。如果要自定义组件渲染输出,则需要将组件包装在函数中并使用
render
选项,以便将除了match
,location
和history
之外的任何其他道具传递给组件。举例说明:2.-使用 withRouter HoC
这个更高阶的组件将注入与
Route
相同的道具。但是,它带有每个文件只能有 1 个 HoC 的限制。3.-使用重定向组件
渲染
<Redirect>
将导航到新位置。但请记住,默认情况下,当前位置被新的替换,如 server-side 重定向(HTTP 3xx)。新位置由to
prop 提供,可以是字符串(重定向到的 URL)或location
对象。如果你想将一个新条目推送到历史上,也要传递一个push
prop 并将其设置为true
4.-通过上下文手动访问路由器
有点气馁,因为上下文仍然是一个实验性的 API,它很可能在未来的 React 版本中 break/change
毋庸置疑,还有其他路由器组件可用于非浏览器生态系统,例如
<NativeRouter>
复制内存中的导航堆栈并以 React Native 平台为目标,可通过react-router-native
包获得。如有任何进一步的参考,请不要犹豫,看看官方文件。还有一个由 co-authors 库创建的视频,它为 react-router v4 提供了很酷的介绍,突出了一些重大变化。
完成任务的最简单方法:
this.props.history.push("/new/url")
注意:
history
prop
从父组件传递到要调用操作的组件。迁移到 React-Router v4 时我遇到了类似的问题,所以我将尝试解释下面的解决方案。
请不要将这个答案视为解决问题的正确方法,我想有一个很好的机会会出现更好的事情,因为 React Router v4 变得更加成熟并且离开了 beta(它甚至可能已经存在,我只是没有发现它) 。
对于上下文,我遇到了这个问题,因为我偶尔会使用
Redux-Saga
以编程方式更改历史记录对象(例如,当用户成功进行身份验证时)。在 React Router 文档中,查看
<Router>
零件,您可以看到您可以通过 prop 传递自己的历史对象。这是解决方案的本质 - 我们从全局模块向React-Router
提供历史对象。脚步:
安装历史记录 npm 模块 -
yarn add history
或npm install history --save
在
App.js
级别文件夹中创建一个名为history.js
的文件(这是我的偏好)现在一切都应该保持同步,你也可以通过编程方式访问历史对象,而不是通过 component/container。
TL; DR:
**简单和陈述性的答案是你需要将<Redirect to= push= />与 setState()**组合使用
完整示例这里。阅读更多这里。
PS。该示例使用ES7 属性初始化程序初始化状态。如果您有兴趣,请查看这里。
第 1 步:在顶部只导入一件事:
第 2 步:在你的路线中,传递历史:
第 3 步:历史记录在下一个组件中被接受为道具的一部分,因此您可以简单地:
这很容易而且非常强大。
这有效:
也可以简单地使用道具:
this.props.history.push('new_url')
我的回答类似于Alex。我不确定为什么 React-Router 这样做变得如此不必要地复杂化。为什么我必须用 HoC 包装我的组件才能访问本质上是全局的?
无论如何,如果你看看他们如何实现<BrowserRouter>,它只是一个围绕历史的小包装。
我们可以将该历史记录拉出来,以便我们可以从任何地方导入它。然而,诀窍在于,如果你正在进行 server-side 渲染并且你试图
import
历史模块,它将无法工作,因为它使用 browser-only API。但这没关系,因为我们通常只会重定向以响应点击或其他 client-side 事件。因此伪造它可能是可以的:在 webpack 的帮助下,我们可以定义一些变量,以便我们了解我们所处的环境:
现在你可以
从任何地方。它只会在服务器上返回一个空模块。
如果你不想使用这些魔法变量,你只需要在需要它的全局对象中(在你的事件处理程序中)。
import
将无效,因为它只适用于 top-level。我已经测试了 v4 几天了......到目前为止我很喜欢它!一段时间后它才有意义。
我也有同样的问题,我发现处理它像下面的工作最好(甚至可能是它的意图)。它使用 state,一个三元运算符和
<Redirect>
。在 constructor()
在 render()
在 clickhandler()
希望能帮助到你。让我知道。
我挣扎了一段时间 - 这么简单,但又如此复杂,因为 ReactJS 只是一种完全不同的编写 Web 应用程序的方式,它对我们老年人来说非常陌生!
我创建了一个单独的组件来抽象掉这个烂摊子:
然后将其添加到
render()
方法:我认为 that_1_covers 大多数情况减去一个我认为非常重要的情况。
这允许我用 actions/calls 编写一个简单的服务,我可以调用它从我想要的任何组件进行导航而不需要在我的组件上做很多 HoC ...
目前尚不清楚为什么没有人提供此解决方案。我希望它有所帮助,如果您发现任何问题,请告诉我。
由于没有其他方法来处理这个可怕的设计,我写了一个使用
withRouter
HOC方法的通用组件。下面的示例是包装button
元素,但您可以更改为您需要的任何可单击元素:用法:
有时我更喜欢按应用程序切换路由然后按按钮,这是一个最适合我的工作示例:
对于那些需要在使用
React Router
或React Router Dom
完全初始化路由器之前重定向的人您可以通过简单地访问历史对象并在app.js
的构造函数中将新状态推送到路由器来提供重定向。考虑以下:在这里,我们希望通过在组件呈现之前与历史对象进行交互来更改依赖于子域的输出路由,我们可以有效地重定向,同时仍然保持我们的路由。