我刚刚react-router
从 v3更换到 v4。
但我不确定如何以编程方式在 a 的成员函数中导航Component
。即在处理一些数据后handleClick()
我想导航到的功能/path/some/where
。我曾经这样做过:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
但是我在 v4 中找不到这样的接口。
如何使用 v4 导航?
我刚刚react-router
从 v3更换到 v4。
但我不确定如何以编程方式在 a 的成员函数中导航Component
。即在处理一些数据后handleClick()
我想导航到的功能/path/some/where
。我曾经这样做过:
import { browserHistory } from 'react-router'
browserHistory.push('/path/some/where')
但是我在 v4 中找不到这样的接口。
如何使用 v4 导航?
如果您的目标是浏览器环境,则需要使用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>
作为props传递给组件(就像您在以前的版本中需要做的那样)。
在 V4 中,为了以编程方式导航,您需要访问history
可通过 React访问的对象,context
只要您将<BrowserRouter>
提供程序组件作为应用程序中最顶层的父组件即可。该库通过上下文公开router
对象,该对象本身包含history
为一个属性。该history
界面提供了多种导航方法,例如push
、replace
和goBack
等。您可以在此处查看整个属性和方法列表。
这是因为使用上下文模型react-router
传递location
给组件。
connect 和观察者都创建组件,其 shouldComponentUpdate 方法对当前的 props 和下一个 props 进行浅层比较。这些组件只会在至少一个 prop 发生变化时重新渲染。这意味着为了确保它们在位置更改时更新,需要为它们提供一个在位置更改时更改的 prop。
解决这个问题的2种方法是:
<Route />
. 当前location
对象是 a<Route>
传递给它渲染的组件的props之一withRouter
,它实际上具有相同的效果并location
作为props 注入撇开这一点不谈,有四种以编程方式导航的方法,按推荐排序:
<Route>
组件<Route />
组件被放置在组件层次结构的顶部,必须事先考虑路由结构。但是,现在您可以在树中的任何位置拥有<Route>
组件,让您可以根据 URL 更好地控制条件渲染。将,和作为props注入到您的组件中。导航方法(例如, , ...)可用作对象的属性。Route
match
location
history
push
replace
goBack
history
有 3 种方法可以Route
通过使用component
,render
或children
props来渲染带有 a 的内容,但不要在同一个Route
. 选择取决于用例,但基本上前两个选项只会在path
匹配 url 位置时呈现您的组件,而children
无论路径是否与位置匹配,都会呈现组件(用于根据 URL 调整 UI匹配)。
如果您想自定义您的组件渲染输出,您需要将您的组件包装在一个函数中并使用该render
选项,以便将您想要的任何其他props传递给您的组件,除了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>
);
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);
Redirect
组件<Redirect>
将导航到新位置。但请记住,默认情况下,当前位置会替换为新位置,例如服务器端重定向 (HTTP 3xx)。新位置由to
prop提供,可以是字符串(要重定向到的 URL)或location
对象。如果您想将新条目推送到历史记录中,请同时传递一个push
props并将其设置为true
<Redirect to="/your-new-location" push />
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,
}),
};
毋庸置疑,还有其他路由器组件旨在用于非浏览器生态系统,例如在内存<NativeRouter>
中复制导航堆栈并以 React Native 平台为目标,可通过 package.json 获得。react-router-native
如需进一步参考,请随时查看官方文档。还有一个由该库的合著者之一制作的视频,该视频提供了对 react-router v4 的非常酷的介绍,突出了一些主要变化。
完成它的最简单方法:
this.props.history.push("/new/url")
笔记:
history
prop
如果操作不可用,您可能希望将from 父组件传递给要调用该操作的组件。我在迁移到 React-Router v4 时遇到了类似的问题,所以我将尝试在下面解释我的解决方案。
请不要认为这个答案是解决问题的正确方法,我想随着 React Router v4 变得更加成熟并离开测试版,很有可能会出现更好的东西(它甚至可能已经存在,只是我没有发现) .
对于上下文,我遇到了这个问题,因为我偶尔会使用Redux-Saga
编程方式更改历史对象(比如用户成功通过身份验证时)。
在 React Router 文档中,查看该<Router>
组件,您会发现您可以通过 prop 传递您自己的历史对象。这是该方案的本质-我们提供的历史对象,以React-Router
从全球module。
yarn add history
或者 npm install history --save
history.js
在您的App.js
级别文件夹中创建一个文件(这是我的偏好)
// src/history.js
import createHistory from 'history/createBrowserHistory';
export default createHistory();`
像这样将这个历史对象添加到你的路由器组件中
// src/App.js
import history from '../your/path/to/history.js;'
<Router history={history}>
// Route tags here
</Router>
调整URL就像通过导入之前,你的世界历史的对象:
import history from '../your/path/to/history.js;'
history.push('new/path/here/');
现在一切都应该保持同步,您还可以访问以编程方式设置历史对象的方法,而不是通过组件/容器。
特尔;博士:
if (navigate) {
return <Redirect to="/" push={true} />
}
简单且声明性的答案是您需要<Redirect to={URL} push={boolean} />
结合使用setState()
push: boolean -如果为真,重定向会将新条目推送到历史记录中,而不是替换当前条目。
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>
)
}
}
附注。该示例使用ES7+ 属性初始化器来初始化状态。如果你有兴趣,也可以看看这里。
useHistory
如果您使用函数组件,请使用钩子您可以使用useHistory
钩子来获取history
实例。
import { useHistory } from "react-router-dom";
const MyComponent = () => {
const history = useHistory();
return (
<button onClick={() => history.push("/about")}>
Click me
</button>
);
}
该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>
);
}
}
withRouter
以注入路由器属性withRouter
包装器将路由器属性注入组件。例如,您可以使用此包装器将路由器注入用户菜单中的注销按钮组件。
import { withRouter } from "react-router";
const LogoutButton = withRouter(({ history }) => {
return (
<button onClick={() => history.push("/login")}>
Logout
</button>
);
});
export default LogoutButton;