Reactjs 使用react router V4以编程方式导航
我刚刚将Reactjs 使用react router V4以编程方式导航,reactjs,ecmascript-6,react-router-v4,Reactjs,Ecmascript 6,React Router V4,我刚刚将react路由器从v3更换为v4。 但是我不知道如何以编程方式在组件的成员函数中导航。 i、 e在handleClick()函数中,我想在处理一些数据后导航到/path/some/where。 我过去常常这样做: 从'react router'导入{browserHistory} browserHistory.push(“/path/some/where”) 但是我在v4中找不到这样的接口。 如何使用v4导航?如果您针对的是浏览器环境,则需要使用react router dom包,而不
react路由器
从v3更换为v4。但是我不知道如何以编程方式在
组件的成员函数中导航。
i、 e在handleClick()
函数中,我想在处理一些数据后导航到/path/some/where
。
我过去常常这样做:
从'react router'导入{browserHistory}
browserHistory.push(“/path/some/where”)
但是我在v4中找不到这样的接口。
如何使用v4导航?如果您针对的是浏览器环境,则需要使用react router dom
包,而不是react router
。他们采用了与React相同的方法,以分离核心(React
)和平台特定的代码(React dom
,React native
),细微的区别是不需要安装两个单独的包,因此环境包包含您需要的所有内容。您可以将其添加到项目中,如下所示:
纱线添加反应器dom
或
npm i react路由器dom
您需要做的第一件事是提供一个
作为应用程序中最顶层的父组件
使用HTML5历史
API并为您管理它,因此您不必担心自己实例化它并将其作为道具传递给
组件(在以前的版本中需要这样做)
在V4中,为了进行编程导航,您需要访问历史记录
对象,该对象可通过React上下文
访问,只要您的应用程序中有一个
提供程序组件作为最顶层的父级。库通过上下文公开路由器
对象,该对象本身包含历史
属性。历史记录
界面提供了多种导航方法,例如推送
、替换
和返回
。您可以检查整个属性和方法列表
Redux/Mobx用户的重要注意事项
如果您在应用程序中使用redux或mobx作为状态管理库,您可能会遇到组件问题,这些组件应该是位置感知的,但在触发URL更新后不会重新呈现。
这是因为react router
使用上下文模型将location
传递给组件
connect和observer都创建了组件,其shouldComponentUpdate方法对当前的道具和下一个道具进行了粗略的比较。只有在至少一个道具发生更改时,这些组件才会重新渲染。这意味着,为了确保它们在位置改变时更新,需要为它们提供一个在位置改变时改变的道具
解决这一问题的两种方法是:
- 将连接的组件包装在无路径的
中。当前的位置
对象是
传递给它呈现的组件的道具之一
- 用
withRouter
高阶组件包装您连接的组件,这实际上具有相同的效果,并作为道具注入location
撇开这一点不谈,按推荐顺序,有四种编程导航方式:
1.-使用
组件可以提升声明式风格。在v4之前,
组件被放置在组件层次结构的顶部,必须事先考虑路由结构。但是,现在您可以在树中的任何位置使用
组件,从而可以根据URL使用更好的控件进行有条件渲染<代码>路由
将匹配
、位置
和历史
作为道具注入组件。导航方法(如push
,replace
,goBack
…)作为历史对象的属性提供
使用路径
渲染某物有三种方法,即使用组件
、渲染
或子级
道具,但在同一路径
中不要使用多个。选择取决于用例,但基本上前两个选项仅在路径
与url位置匹配时才会呈现组件,而对于子项
,无论路径是否与位置匹配,都会呈现组件(用于根据url匹配调整UI)
如果要自定义组件渲染输出,则需要将组件封装在函数中,并使用渲染
选项,以便向组件传递除匹配
、位置
和历史
之外所需的任何其他道具。举例说明:
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>
);
3.-使用重定向
组件呈现
将导航到新位置。但是请记住,默认情况下,当前位置会被新位置替换,就像服务器端重定向(HTTP 3xx)一样。新位置由to
prop提供,可以是字符串(要重定向到的URL)或location
对象。如果您想将一个新条目推送到历史记录中,请同时传递一个push
prop并将其设置为true
<Redirect to="/your-new-location" push />
不用说,还有其他路由器组件是为非浏览器生态系统设计的,例如
,它复制内存中的导航堆栈,并以React-Native平台为目标,可通过React-Router-Native
包获得
对于任何进一步的参考,请毫不犹豫地查看。还有一个由该库的一位合著者编写的示例,它对react路由器v4 highlig进行了非常酷的介绍
<Redirect to="/your-new-location" push />
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,
}),
};
// 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>
import history from '../your/path/to/history.js;'
history.push('new/path/here/');
this.state = {
redirectTo: null
}
this.clickhandler = this.clickhandler.bind(this);
render(){
return (
<div>
{ this.state.redirectTo ?
<Redirect to={{ pathname: this.state.redirectTo }} /> :
(
<div>
..
<button onClick={ this.clickhandler } />
..
</div>
)
}
this.setState({ redirectTo: '/path/some/where' });
if (navigate) {
return <Redirect to="/" push={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>
)
}
}
import { Component } from 'react'
import { BrowserRouter as Router, Link } from 'react-router-dom'
class App extends Component {
constructor(props) {
super(props)
/** @type BrowserRouter */
this.router = undefined
}
async handleSignFormSubmit() {
await magic()
this.router.history.push('/')
}
render() {
return (
<Router ref={ el => this.router = el }>
<Link to="/signin">Sign in</Link>
<Route path="/signin" exact={true} render={() => (
<SignPage onFormSubmit={ this.handleSignFormSubmit } />
)} />
</Router>
)
}
}
// history.js
if(__SERVER__) {
module.exports = {};
} else {
module.exports = require('history').createBrowserHistory();
}
plugins: [
new DefinePlugin({
'__SERVER__': 'false',
'__BROWSER__': 'true', // you really only need one of these, but I like to have both
}),
import history from './history';
// 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
};
<LinkButton className="btn btn-primary" to="/location">
Button Text
</LinkButton>
import React from 'react';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router-dom';
const NavButton = (props) => (
<Button onClick={() => props.history.push(props.to)}>
{props.children}
</Button>
);
NavButton.propTypes = {
history: PropTypes.shape({
push: PropTypes.func.isRequired
}),
to: PropTypes.string.isRequired
};
export default withRouter(NavButton);
<NavButton to="/somewhere">Click me</NavButton>
import {Route} from 'react-router-dom';
<Route
exact
path='/posts/add'
render={({history}) => (
<PostAdd history={history} />
)}
/>
this.props.history.push('/');
import { withRouter } from 'react-router-dom';
const SomeComponent = withRouter(({ history }) => (
<div onClick={() => history.push('/path/some/where')}>
some clickable element
</div>);
);
export default SomeComponent;
// 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");
function getSubdomain(hostname) {
let regexParse = new RegExp('[a-z\-0-9]{2,63}\.[a-z\.]{2,5}$');
let urlParts = regexParse.exec(hostname);
return hostname.replace(urlParts[0], '').slice(0, -1);
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
hostState: true
};
if (getSubdomain(window.location.hostname).length > 0) {
this.state.hostState = false;
window.history.pushState('', '', './login');
} else {
console.log(getSubdomain(window.location.hostname));
}
}
render() {
return (
<BrowserRouter>
{this.state.hostState ? (
<div>
<Route path="/login" component={LoginContainer}/>
<Route path="/" component={PublicContainer}/>
</div>
) : (
<div>
<Route path="/login" component={LoginContainer}/>
</div>
)
}
</BrowserRouter>)
}
}
window.history.pushState('', '', './login');
import { useHistory } from "react-router-dom";
const MyComponent = () => {
const history = useHistory();
return (
<button onClick={() => history.push("/about")}>
Click me
</button>
);
}
class HomePage extends React.Component {
render() {
const { history } = this.props;
return (
<div>
<button onClick={() => history.push("/projects")}>
Projects
</button>
</div>
);
}
}
import { withRouter } from "react-router";
const LogoutButton = withRouter(({ history }) => {
return (
<button onClick={() => history.push("/login")}>
Logout
</button>
);
});
export default LogoutButton;
this.props.history.push("/url")
import {withRouter} from 'react-router-dom'
export default withRouter(MyComponent)
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>
);
}