如果你的目标是浏览器环境,你需要使用react-router-dom 包,而不是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> provider 组件作为最顶层应用程序中的父级。该库通过上下文公开router 对象,该对象本身包含history 作为属性。 history 接口提供了多种导航方法,例如push、replace 和goBack 等。您可以查看属性和方法的完整列表here。
Redux/Mobx 用户重要提示
如果您在应用程序中使用 redux 或 mobx 作为状态管理库,您可能会遇到组件应该具有位置感知但在触发 URL 更新后不会重新渲染的问题
这是因为react-router 使用上下文模型将location 传递给组件。
connect 和 observer 都创建组件,其 shouldComponentUpdate 方法对其当前 props 和下一个 props 进行浅层比较。这些组件只会在至少一个道具发生变化时重新渲染。这意味着为了确保它们在位置更改时更新,需要为它们提供在位置更改时更改的道具。
解决这个问题的两种方法是:
- 将您的 connected 组件包装在无路径
<Route /> 中。当前的location 对象是<Route> 传递给它所呈现的组件的道具之一
- 用
withRouter 高阶组件包装你的 connected 组件,实际上具有相同的效果并将location 作为道具注入
除此之外,有四种以编程方式导航的方法,按推荐排序:
1.- 使用<Route> 组件
它提倡声明式风格。在 v4 之前,<Route /> 组件被放置在组件层次结构的顶部,必须事先考虑您的路由结构。但是,现在您可以在树中anywhere 拥有<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>
);
2.- 使用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);
3.- 使用Redirect 组件
渲染
<Redirect> 将导航到新位置。但请记住,
默认情况下,当前位置会被新位置替换,例如服务器端重定向 (HTTP 3xx)。新位置由
to 属性提供,它可以是字符串(重定向到的 URL)或
location 对象。如果您想
将新条目推送到历史记录,请同时传递
push 属性并将其设置为
true
<Redirect to="/your-new-location" push />
4.- 通过上下文手动访问 router
有点气馁,因为
context 仍然是一个实验性 API,它可能会在未来的 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,
}),
};
毋庸置疑,还有其他用于非浏览器生态系统的路由器组件,例如 <NativeRouter>,它复制了一个导航堆栈在内存中并以 React Native 平台为目标,可通过 @ 获得987654390@包。
如需进一步参考,请随时查看official docs。还有一个 video 由该库的一位合著者制作,提供了对 react-router v4 的非常酷的介绍,突出了一些主要变化。