使用反应路由器 V4 以编程方式导航 [英] Programmatically navigate using react router V4

查看:21
本文介绍了使用反应路由器 V4 以编程方式导航的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚将 react-router 从 v3 替换为 v4.
但我不确定如何以编程方式在 Component 的成员函数中导航.即在 handleClick() 函数中,我想在处理一些数据后导航到 /path/some/where.我曾经这样做过:

import { browserHistory } from 'react-router'browserHistory.push('/path/some/where')

但是我在v4中找不到这样的接口.
如何使用 v4 导航?

解决方案

如果你的目标是浏览器环境,你需要使用 react-router-dom 包,而不是 react-router.他们遵循与 React 相同的方法,以便将核心 (react) 和特定于平台的代码 (react-dom, react-native ) 的细微差别,您不需要安装两个单独的包,因此环境包包含您需要的一切.您可以将其添加到您的项目中:

yarn 添加 react-router-dom

npm i react-router-dom

您需要做的第一件事是提供一个 作为应用程序中最顶层的父组件. 使用 HTML5 history API 并为您管理它,因此您不必担心自己实例化它并将其传递给 <BrowserRouter> 组件作为道具(正如您在以前的版本中需要做的那样).

在 V4 中,为了以编程方式导航,您需要访问 history 对象,该对象可通过 React context 获得,只要您有 ; provider 组件作为应用程序中最顶层的父组件.该库通过上下文公开 router 对象,该对象本身包含 history 作为属性.history 界面提供了多种导航方法,例如 pushreplacegoBack 等.您可以在此处查看整个属性和方法列表.

Redux/Mobx 用户的重要提示

如果您在应用程序中使用 redux 或 mobx 作为状态管理库,您可能会遇到应该感知位置但在触发 URL 更新后未重新呈现的组件的问题>

发生这种情况是因为 react-router 使用上下文模型将 location 传递给组件.

<块引用>

connect 和observer 都创建组件,其shouldComponentUpdate 方法对当前的props 和下一个props 进行浅层比较.这些组件只会在至少一个 prop 发生变化时重新渲染.这意味着为了确保它们在位置更改时更新,需要为它们提供一个在位置更改时更改的 prop.

解决这个问题的两种方法是:

  • 将您的连接组件包装在一个无路径的中.当前 location 对象是 传递给它呈现的组件的 props 之一
  • withRouter 高阶组件包裹你的 connected 组件,这实际上具有相同的效果并注入 location 作为 prop

抛开这些不谈,有四种以编程方式导航的方法,按推荐排序:

1.- 使用 组件

它促进了声明式风格.在 v4 之前,<Route/> 组件位于组件层次结构的顶部,必须事先考虑路由结构.但是,现在您可以在树中任何地方拥有 组件,让您可以根据 URL 更好地控制条件渲染.Routematchlocationhistory 作为道具注入到您的组件中.导航方法(例如 pushreplacegoBack...)可作为 history 的属性使用对象.

有 3 种方法可以使用 Route 渲染某些内容,分别使用 componentrenderchildrenprops,但不要在同一个 Route 中使用多个.选择取决于用例,但基本上前两个选项只会在 path 匹配 url 位置时呈现您的组件,而对于 children 组件将被呈现路径是否与位置匹配(用于根据 URL 匹配调整 UI).

如果你想自定义你的组件渲染输出,你需要将你的组件包装在一个函数中并使用 render 选项,以便将任何除了 matchlocationhistory 之外,您想要的其他道具.举例说明:

import { BrowserRouter as Router } from 'react-router-dom'const ButtonToNavigate = ({ title, history }) =>(<按钮类型=按钮"onClick={() =>history.push('/my-new-location')}>{标题});const SomeComponent = () =>(<Route path="/" render={(props) =><ButtonToNavigate {...props} title="在别处导航"/>}/>)const App = () =>(<路由器><某些组件/>//注意在 v4 中我们可以让任何其他组件交错<另一个组件/></路由器>);

2.- 使用 withRouter HoC

这个高阶组件将注入与 Route 相同的 props.但是,它存在每个文件只能有 1 个 HoC 的限制.

import { withRouter } from 'react-router-dom'const ButtonToNavigate = ({ history }) =>(<按钮类型=按钮"onClick={() =>history.push('/my-new-location')}>导航);ButtonToNavigate.propTypes = {历史:React.PropTypes.shape({推送:React.PropTypes.func.isRequired,}),};导出默认 withRouter(ButtonToNavigate);

3.- 使用 Redirect 组件

渲染 将导航到新位置.但请记住,默认情况下,当前位置会替换为新位置,例如服务器端重定向 (HTTP 3xx).新位置由 to 属性提供,它可以是一个字符串(重定向到的 URL)或一个 location 对象.如果您想将新条目推送到历史记录,请同时传递一个 push 属性并将其设置为 true

4.- 通过上下文手动访问 router

有点气馁,因为 context 仍然是一个实验性的 API,它很可能在 React 的未来版本中被破坏/改变

const ButtonToNavigate = (props, context) =>(<按钮类型=按钮"onClick={() =>context.router.history.push('/my-new-location')}>导航到新位置);ButtonToNavigate.contextTypes = {路由器:React.PropTypes.shape({历史:React.PropTypes.object.isRequired,}),};

不用说,还有其他路由器组件是为非浏览器生态系统设计的,例如 复制导航堆栈在内存中和目标 React Native 平台,可通过 react-router-native 包获得.

如需进一步参考,请随时查看官方文档.还有一个视频,由该库的一位合著者制作,提供了一个react-router v4 的介绍非常棒,重点介绍了一些主要变化.

I have just replaced react-router from v3 to v4.
But I am not sure how to programmatically navigate in the member function of a Component. i.e in handleClick() function I want to navigate to /path/some/where after processing some data. I used to do that by:

import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')

But I can't find such interfaces in v4.
How can I navigate using v4?

解决方案

If you are targeting browser environments, you need to use react-router-dom package, instead of react-router. They are following the same approach as React did, in order to separate the core, (react) and the platform specific code, (react-dom, react-native ) with the subtle difference that you don't need to install two separate packages, so the environment packages contain everything you need. You can add it to your project as:

yarn add react-router-dom

or

npm i react-router-dom

The first thing you need to do is to provide a <BrowserRouter> as the top most parent component in your application. <BrowserRouter> uses the HTML5 history API and manages it for you, so you don't have to worry about instantiating it yourself and passing it down to the <BrowserRouter> component as a prop (as you needed to do in previous versions).

In V4, for navigating programatically you need to access the history object, which is available through React context, as long as you have a <BrowserRouter> provider component as the top most parent in your application. The library exposes through context the router object, that itself contains history as a property. The history interface offers several navigation methods, such as push, replace and goBack, among others. You can check the whole list of properties and methods here.

Important Note to Redux/Mobx users

If you are using redux or mobx as your state management library in your application, you may have come across issues with components that should be location-aware but are not re-rendered after triggering an URL update

That's happening because react-router passes location to components using the context model.

Both connect and observer create components whose shouldComponentUpdate methods do a shallow comparison of their current props and their next props. Those components will only re-render when at least one prop has changed. This means that in order to ensure they update when the location changes, they will need to be given a prop that changes when the location changes.

The 2 approaches for solving this are:

  • Wrap your connected component in a pathless <Route />. The current location object is one of the props that a <Route> passes to the component it renders
  • Wrap your connected component with the withRouter higher-order component, that in fact has the same effect and injects location as a prop

Setting that aside, there are four ways to navigate programatically, ordered by recommendation:

1.- Using a <Route> Component

It promotes a declarative style. Prior to v4, <Route /> components were placed at the top of your component hierarchy, having to think of your routes structure beforehand. However, now you can have <Route> components anywhere in your tree, allowing you to have a finer control for conditionally rendering depending on the URL. Route injects match, location and history as props into your component. The navigation methods (such as push, replace, goBack...) are available as properties of the history object.

There are 3 ways to render something with a Route, by using either component, render or children props, but don't use more than one in the same Route. The choice depends on the use case, but basically the first two options will only render your component if the path matches the url location, whereas with children the component will be rendered whether the path matches the location or not (useful for adjusting the UI based on URL matching).

If you want to customise your component rendering output, you need to wrap your component in a function and use the render option, in order to pass to your component any other props you desire, apart from match, location and history. An example to illustrate:

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>
);

2.- Using withRouter HoC

This higher order component will inject the same props as Route. However, it carries along the limitation that you can have only 1 HoC per file.

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);

3.- Using a Redirect component

Rendering a <Redirect> will navigate to a new location. But keep in mind that, by default, the current location is replaced by the new one, like server-side redirects (HTTP 3xx). The new location is provided by to prop, that can be a string (URL to redirect to) or a location object. If you want to push a new entry onto the history instead, pass a push prop as well and set it to true

<Redirect to="/your-new-location" push />

4.- Accessing router manually through context

A bit discouraged because context is still an experimental API and it is likely to break/change in future releases of React

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,
  }),
};

Needless to say there are also other Router components that are meant to be for non browser ecosystems, such as <NativeRouter> that replicates a navigation stack in memory and targets React Native platform, available through react-router-native package.

For any further reference, don't hesitate to take a look at the official docs. There is also a video made by one of the co-authors of the library that provides a pretty cool introduction to react-router v4, highlighting some of the major changes.

这篇关于使用反应路由器 V4 以编程方式导航的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆