admin管理员组文章数量:1129621
I have a component that receives through props a <Link/>
object from react-router. Whenever the user clicks on a 'next' button inside this component I want to invoke <Link/>
object manually.
Right now, I'm using refs to access the backing instance and manually clicking on the 'a' tag that <Link/>
generates.
Question: Is there a way to manually invoke the Link (e.g. this.props.next.go
)?
This is the current code I have:
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />
//in Document.js
...
var Document = React.createClass({
_onClickNext: function() {
var next = this.refs.next.getDOMNode();
next.querySelectorAll('a').item(0).click(); //this sounds like hack to me
},
render: function() {
return (
...
<div ref="next">{this.props.next} <img src="rightArrow.png" onClick={this._onClickNext}/></div>
...
);
}
});
...
This is the code I would like to have:
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />
//in Document.js
...
var Document = React.createClass({
render: function() {
return (
...
<div onClick={this.props.next.go}>{this.props.next.label} <img src="rightArrow.png" /> </div>
...
);
}
});
...
I have a component that receives through props a <Link/>
object from react-router. Whenever the user clicks on a 'next' button inside this component I want to invoke <Link/>
object manually.
Right now, I'm using refs to access the backing instance and manually clicking on the 'a' tag that <Link/>
generates.
Question: Is there a way to manually invoke the Link (e.g. this.props.next.go
)?
This is the current code I have:
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />
//in Document.js
...
var Document = React.createClass({
_onClickNext: function() {
var next = this.refs.next.getDOMNode();
next.querySelectorAll('a').item(0).click(); //this sounds like hack to me
},
render: function() {
return (
...
<div ref="next">{this.props.next} <img src="rightArrow.png" onClick={this._onClickNext}/></div>
...
);
}
});
...
This is the code I would like to have:
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
<Document next={sampleLink} />
//in Document.js
...
var Document = React.createClass({
render: function() {
return (
...
<div onClick={this.props.next.go}>{this.props.next.label} <img src="rightArrow.png" /> </div>
...
);
}
});
...
Share
Improve this question
edited Dec 29, 2022 at 3:19
starball
49.2k28 gold badges194 silver badges865 bronze badges
asked Mar 24, 2015 at 23:21
Alan SouzaAlan Souza
7,79510 gold badges50 silver badges72 bronze badges
9 Answers
Reset to default 320React Router v6.8 - React 18+ (updated 02/24/2023)
import React from 'react';
import {useNavigate} from 'react-router-dom';
export default function StackOverflowExample() {
const navigate = useNavigate();
const handleOnClick = () => navigate('/sample');
return (
<button type="button" onClick={handleOnClick}>
Go home
</button>
);
}
Docs: https://reactrouter.com/en/main/hooks/use-navigate
React Router v6 - React 17+
import React, {useCallback} from 'react';
import {useNavigate} from 'react-router-dom';
export default function StackOverflowExample() {
const navigate = useNavigate();
const handleOnClick = useCallback(() => navigate('/sample', {replace: true}), [navigate]);
return (
<button type="button" onClick={handleOnClick}>
Go home
</button>
);
}
Note: For this answer, the one major change between v6 and v5 is useNavigate
is now the preferred React hook. useHistory
is deprecated and not recommended.
React Router v5 - React 16.8+ with Hooks
If you're leveraging React Hooks, you can take advantage of the useHistory
API that comes from React Router v5.
import React, {useCallback} from 'react';
import {useHistory} from 'react-router-dom';
export default function StackOverflowExample() {
const history = useHistory();
const handleOnClick = useCallback(() => history.push('/sample'), [history]);
return (
<button type="button" onClick={handleOnClick}>
Go home
</button>
);
}
Another way to write the click handler if you don't want to use useCallback
const handleOnClick = () => history.push('/sample');
React Router v4 - Redirect Component
The v4 recommended way is to allow your render method to catch a redirect. Use state or props to determine if the redirect component needs to be shown (which then trigger's a redirect).
import { Redirect } from 'react-router';
// ... your class implementation
handleOnClick = () => {
// some action...
// then redirect
this.setState({redirect: true});
}
render() {
if (this.state.redirect) {
return <Redirect push to="/sample" />;
}
return <button onClick={this.handleOnClick} type="button">Button</button>;
}
Reference: https://reacttraining.com/react-router/web/api/Redirect
React Router v4 - Reference Router Context
You can also take advantage of Router
's context that's exposed to the React component.
static contextTypes = {
router: PropTypes.shape({
history: PropTypes.shape({
push: PropTypes.func.isRequired,
replace: PropTypes.func.isRequired
}).isRequired,
staticContext: PropTypes.object
}).isRequired
};
handleOnClick = () => {
this.context.router.push('/sample');
}
This is how <Redirect />
works under the hood.
Reference: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/modules/Redirect.js#L46,L60
React Router v4 - Externally Mutate History Object
If you still need to do something similar to v2's implementation, you can create a copy of BrowserRouter
then expose the history
as an exportable constant. Below is a basic example but you can compose it to inject it with customizable props if needed. There are noted caveats with lifecycles, but it should always rerender the Router, just like in v2. This can be useful for redirects after an API request from an action function.
// browser router file...
import createHistory from 'history/createBrowserHistory';
import { Router } from 'react-router';
export const history = createHistory();
export default class BrowserRouter extends Component {
render() {
return <Router history={history} children={this.props.children} />
}
}
// your main file...
import BrowserRouter from './relative/path/to/BrowserRouter';
import { render } from 'react-dom';
render(
<BrowserRouter>
<App/>
</BrowserRouter>
);
// some file... where you don't have React instance references
import { history } from './relative/path/to/BrowserRouter';
history.push('/sample');
Latest BrowserRouter
to extend: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/modules/BrowserRouter.js
React Router v2
Push a new state to the browserHistory
instance:
import {browserHistory} from 'react-router';
// ...
browserHistory.push('/sample');
Reference: https://github.com/reactjs/react-router/blob/master/docs/guides/NavigatingOutsideOfComponents.md
React Router 4 includes a withRouter HOC that gives you access to the history
object via this.props
:
import React, {Component} from 'react'
import {withRouter} from 'react-router-dom'
class Foo extends Component {
constructor(props) {
super(props)
this.goHome = this.goHome.bind(this)
}
goHome() {
this.props.history.push('/')
}
render() {
<div className="foo">
<button onClick={this.goHome} />
</div>
}
}
export default withRouter(Foo)
In the version 5.x, you can use useHistory
hook of react-router-dom
:
// Sample extracted from https://reacttraining.com/react-router/core/api/Hooks/usehistory
import { useHistory } from "react-router-dom";
function HomeButton() {
const history = useHistory();
function handleClick() {
history.push("/home");
}
return (
<button type="button" onClick={handleClick}>
Go home
</button>
);
}
https://github.com/rackt/react-router/blob/bf89168acb30b6dc9b0244360bcbac5081cf6b38/examples/transitions/app.js#L50
or you can even try executing onClick this (more violent solution):
window.location.assign("/sample");
Answers here are outdated.
React Router 6
useHistory
is deprecated v6 uses the useNavigate
hook instead.
import { useNavigate } from 'react-router-dom'
const navigate = useNavigate()
navigate(`/somewhere`, { replace: true })
Ok, I think I was able to find a proper solution for that.
Now, instead of sending <Link/>
as prop to Document, I send <NextLink/>
which is a custom wrapper for the react-router Link. By doing that, I'm able to have the right arrow as part of the Link structure while still avoiding to have routing code inside Document object.
The updated code looks like follows:
//in NextLink.js
var React = require('react');
var Right = require('./Right');
var NextLink = React.createClass({
propTypes: {
link: React.PropTypes.node.isRequired
},
contextTypes: {
transitionTo: React.PropTypes.func.isRequired
},
_onClickRight: function() {
this.context.transitionTo(this.props.link.props.to);
},
render: function() {
return (
<div>
{this.props.link}
<Right onClick={this._onClickRight} />
</div>
);
}
});
module.exports = NextLink;
...
//in MasterPage.js
var sampleLink = <Link to="/sample">Go To Sample</Link>
var nextLink = <NextLink link={sampleLink} />
<Document next={nextLink} />
//in Document.js
...
var Document = React.createClass({
render: function() {
return (
...
<div>{this.props.next}</div>
...
);
}
});
...
P.S: If you are using the latest version of react-router you may need to use this.context.router.transitionTo
instead of this.context.transitionTo
. This code will work fine for react-router version 0.12.X.
React Router 4
You can easily invoke the push method via context in v4:
this.context.router.push(this.props.exitPath);
where context is:
static contextTypes = {
router: React.PropTypes.object,
};
If you'd like to extend
the Link
component to utilise some of the logic in it's onClick()
handler, here's how:
import React from 'react';
import { Link } from "react-router-dom";
// Extend react-router-dom Link to include a function for validation.
class LinkExtra extends Link {
render() {
const linkMarkup = super.render();
const { validation, ...rest} = linkMarkup.props; // Filter out props for <a>.
const onclick = event => {
if (!this.props.validation || this.props.validation()) {
this.handleClick(event);
} else {
event.preventDefault();
console.log("Failed validation");
}
}
return(
<a {...rest} onClick={onclick} />
)
}
}
export default LinkExtra;
Usage
<LinkExtra to="/mypage" validation={() => false}>Next</LinkExtra>
again this is JS :) this still works ....
var linkToClick = document.getElementById('something');
linkToClick.click();
<Link id="something" to={/somewhaere}> the link </Link>
本文标签: javascriptHow to manually invoke Link in ReactrouterStack Overflow
版权声明:本文标题:javascript - How to manually invoke Link in React-router? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736747269a1950848.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论