React Router Link Right Click does not work - javascript

I am having an issue where the "right click" on the links that are created with React Router Link tags.
I want to be able to right click on those links and select "Open Link in New Tab" option.
Could anyone please help me with this issue?
Here is my code:
redirectUrl = (e) => {
let url = e.currentTarget.getAttribute("dataattrurl");
browserHistory.push({
pathname : url,
query : '',
state : {}
});
}
const listItems = readingHistory.map((item, index) => {
return (
<li key={index} role="listitem">
<Link className="linkPointer" onClick={this.redirectUrl} dataattrurl={`/document/${item.resId}`} onContextMenu={this.contextMenu}>
{item.title}
</Link>
</li>
);
});

The problem is that you are handling the click event with an onClick rather than with an href (to for Link), so the browser does not register this as a link to another page but rather an element with a click event listener.
What you should do is make use of the to attribute of Link, which is basically the href for a regular a tag. See the docs here: https://reacttraining.com/react-router/web/api/Link
This will also result in much cleaner code. All your code can be reduced to:
const listItems = readingHistory.map((item, index) => {
return (
<li key={ index } role="listitem">
<Link className="linkPointer" to={ `/document/${item.resId}` } onContextMenu={ this.contextMenu }>
{ item.title }
</Link>
</li>
);
});
So the redirectUrl can be removed entirely.

Related

How to set isActive on active link in a map loop using NEXTUI navbar?

I'm using the new NEXTUI navbar: https://nextui.org/docs/components/navbar
I want to set isActive property on the active link and there isn't much help to get from Google so I hope someone here have used it or knows how to do so. I'm using Next.js
A portion of the code:
<Navbar.Content
enableCursorHighlight
activeColor="primary"
hideIn="xs"
variant="highlight-rounded"
>
{navigation.map((item, index) => (
<Navbar.Link key={index} href={item.link}>
{item.title}
</Navbar.Link>
))}
</Navbar.Content>
EDIT: When I add isActive in the map loop, it effects all. I want to set isActiveon the clicked (active link) one at a time. If I didn't loop my nav links (which is coming from backend) I could set IsActive property on one but then its just that one that have isActive even if I click on other links.
You have to use a specific condition in your map to check if you are on the correct route.
For example: you can use the next/router and compare it to the link property of the item.
const { asPath } = useRouter();
.
.
.
//inside return body
....
{navigation.map((item, index) => {
if(asPath === item.link)
return(<Navbar.Link isActive key={index} href={item.link}>
{item.title}
</Navbar.Link>);
});
else
return(<Navbar.Lin key={index} href=. {item.link}>
{item.title}
</Navbar.Link>);
})
}
similar to the answer above but without the if/else in the return
{navigation.map((item, index) => (
<Navbar.Link
isActive={asPath === item.link}
key={index}
href={item.link}
>
{item.title}
</Navbar.Link>);
))}

React - navigate to section from other link

I have navigation in my app, one link has got attr to='/' and I have method onClick that is taking me to section about. When I am on main Page '/' it works, but when I am on different pages nav works but only returning me to main page but I want also to take me to section. I can do this after second click. How can i solve this issue ?
<li>
<NavLink to="/" activeClassName={window.pageYOffset > this.scroll && "active-main"} className="link-left" onClick={this.goToAbout}>
O Nas
</NavLink>
</li>
Method:
goToAbout = () => {
window.scrollTo(0, this.scroll);
};
ComponentDidMount:
this.aboutUs = document.getElementById("aboutUs");
this.scroll = this.aboutUs.offsetTop - 100;
You need to prevent the default behavior so your link won't go to "/" anymore, only scrolls
goToAbout = (event) => {
event.preventDefault();
window.scrollTo(0, this.scroll);
};

React.js, JavaScript Get Img by clicking a parent element from an array

I'm trying to make a select component which works as a navigation.
When I click one of menu list, the clickedValue(img and text) should be on the button element.
I found a way to show clicked text value which is "e.currentTarget.textContent" but for the img, I cannot find a way...
I've tried innerHTML which show me literally link source, but not actual image.
I didn't write some other codes that you don't need, if that bothers you, sorry xD
state = {
clickedValue : 'cryptocurrency'
}
handleSelected = (e) => {
const { clickedValue } = this.state;
this.setState({
clickedValue : e.currentTarget.textContent
})
}
const menu = [{
link : '/service',
img : some link,
title : 'Cryptocurrency'
},{
link : '/service/wallet',
img : some link2,
title : 'Wallet'
}, {
link : '/service/ico',
img : some link3,
title : 'Ico'
}]
<button>Clicked Value which is img and text here</button>
{menu.map(
(menu) => (
<li onClick={handleSelected} className={cx('list')}><NavLink exact to={menu.link}><img src={menu.img} alt={menu.title}/>{menu.title}</NavLink></li>
)
)}
I'm sure you could make it work the way you are intending, but why not simply pass the menu value to handleSelected?
<li onClick={() => this.handleSelected(menu)}
Saves a lot of time for you :)

How do I prevent an entire list from re-rendering when state of one component changes?

I have a list component that fetches data and maps the results over card-like child components to create a list of "cards". Below is a example:
class Card extends Component {
constructor(props) {
super(props);
this.state = {
activeTab: 1
};
}
setActiveTab = (activeTab) => {
this.setState({ activeTab });
}
render() {
const activeTab = this.state.activeTab;
return (
<div className="card">
<ul className="nav nav-tabs card-header-tabs">
<li
className="nav-item"
key={ 1 }
onClick={ () => this.setActiveTab(1) }
>
<a className="nav-link" href="#">Overview</a>
</li>
<li
className="nav-item"
key={ 2 }
onClick={ () => this.setActiveTab(2) }
>
<a className="nav-link" href="#">Data</a>
</li>
<li
className="nav-item"
key={ 3 }
onClick={ () => this.setActiveTab(3) }
>
<a className="nav-link" href="#">Edit</a>
</li>
</ul>
<h3 className="card-title">{ this.props.title }</h3>
{ activeTab === 1 &&
<h5 className="card-text">
{ this.props.body }
</h5>
}
{ activeTab === 2 &&
<div className="card-data">
<a>Yes: { this.props.yes }</a>
<a>No: { this.props.no }</a>
</div>
}
{ activeTab === 3 &&
<div>
<a
href="/cards"
onClick={ this.props.onDelete }
className="delete-card"
>
Delete
</a>
</div>
}
</div>
)
}
}
export default Card;
class CardList extends Component {
componentDidMount() {
this.props.fetchCards();
}
renderCards() {
return this.props.cards.reverse().map(({ _id, title, body, yes, no }) => {
return (
<Card
key={_id}
title={title}
body={body}
yes={yes}
no={no}
onDelete={() => this.props.deleteSurvey(_id)}
/>
);
});
}
render() {
return (
<div className="container">
<div className="row">{this.renderCards()}</div>
</div>
);
}
}
Each card has tabs, clicking a tab determine which text is shown in each particular card. The tab/toggle is working, but my issue is that the entire list is re-rendering when the tab is clicked. So if you are at the bottom of the list, the re-render brings you back to the top of the list.
I've tried implementing componentShouldUpdate, but with no success thus far. I would like for the card to toggle it's content and the list remain in place. Is using the shouldUpdate lifecycle method the correct route? Or is there a better approach?
In your <a> anchor tag you have href="#"` which will always re-direct you to a new link. (# will re-direct to current page re-rendering everything).
Easiest Solution is to remove href="#" which will remove your cursor: pointer; styling but you can re-add that back into your
nav-item classname.
Another simple solution is you can move the onClick into the anchor tag and adding evt.preventDefault() (Which prevents the event handler from doing the default action which is loading the page to the href) However this will make it so that you have to click the anchor tag so if you have padding between the <li> and <a> this might not be your best solution.
<li
className="nav-item"
key={ 3 }
>
<a
className="nav-link"
href="#"
onClick={ (e) => { e.preventDefault(); this.setActiveTab(3); } }
>
Edit
</a>
</li>
However Thai Duong Tran made a good point where you don't want to re-create the function every time.
Best solution is to move your anonymous function into a class function. (This solution also removes the href="#" so you need to add cursor: pointer; into your css if you want that style)
<li
className="nav-item"
data-tab={ 1 }
onClick={this.onNavClick}
>
<a className="nav-link">Overview</a>
</li>
onNavClick = (evt) => {
this.setState({activeTab: evt.target.dataset.tab});
}
Also your delete action has the same issue where you added a href="/card" so you want to be careful with that.
If you want to have route actions to move to different pages/URL. You should look into adding react-router
I think it's the prbolem
onClick={ () => this.setActiveTab(2) }
Essentially, React decides to re-render a component when it detects a change in component state or props, and it only does shallow comparison for object.
As you are using closures, these function is dynamically re-created every time the Card component render function is called. React detects a new object (in JS, function is treated as object) passed to the li element, then it redraws it.
To solve this problem you can do something like:
<li className="nav-item" data-tab={ 1 }
onClick={this.navLinkClickHandler}>
<a className="nav-link" href="#">Overview</a>
</li>
Then have navLinkClickHandler defined in your component:
navLinkClickHandler = (evt) => this.setState({activeTab: evt.target.dataset.tab})
More on React reconcilation can be found here:
https://reactjs.org/docs/reconciliation.html
And about using closure in render function:
https://reda-bx.gitbooks.io/react-bits/content/conventions/08.closures-in-render.html
Try this code inside CARD component (If you have not tried it already). Might work fine.
shouldComponentUpdate(nextProps,nextState){
if(this.state.activeTab === nextState.activeTab ){
return false
} else {
return true
}
}

Easier way to to disable link in React?

I want to disable Link in some condition:
render() {
return (<li>{this.props.canClick ?
<Link to="/">Test</Link> :
<a>Test</a>}
</li>)
}
<Link> must specify to, so I can not disable <Link> and I have to use <a>
You could just set set the link's onClick property:
render () {
return(
<li>
{
this.props.notClickable
? <Link to="/" className="disabledCursor" onClick={ (event) => event.preventDefault() }>Link</Link>
: <Link to="/" className="notDisabled">Link</Link>
}
</li>
);
};
Then disable the hover effect via css using the cursor property.
.disabledCursor {
cursor: default;
}
I think that should do the trick?
Your code already seems quite clean and slim. Not sure why you want an "easier" way. I'd do it exactly how you're doing it.
However, here are a few alternatives:
Using pointer-events
This one is probably as short and sweet as you can get it:
render() {
return (<li>
<Link to="/" style={this.props.canClick ? {pointerEvents: "none"} : null}>Test</Link>
</li>)
}
Using onClick listener
As an alternative, you could use a generic <a> tag and add an onClick listener for the condition. This is probably better suited if you have lots of links that you want to control their state because you could use the same function on all of them.
_handleClick = () => {
if(this.props.canClick) {
this.context.router.push("/");
}
}
render() {
return (
<li>
<a onClick={this._handleClick}>Test</a>});
</li>
);
}
The above will work assuming you are using context.router. If not, add to your class:
static contextTypes = {
router: React.PropTypes.object
}
Better version of OP code
As I mentioned above, I still think your approach is the "best". You could replace the anchor tag with a span, to get rid of the styling for a disabled link (e.g pointer cursor, hover effects, etc).
render() {
return (<li>{this.props.canClick ?
<Link to="/">Test</Link> :
<span>Test</span>}
</li>)
}
A good solution is using onClick() with event object. just do this in your jsx:
<Link to='Everything' onClick={(e) => this._onClick(e)}
and in your _onClick function:
_onClick = (e) => {
e.preventDefault()
}
Complete Example in React:
import React, { Component } from 'react'
import {Link} from 'react-router-dom'
export default class List extends Component {
_onClick = (e) => {
e.preventDefault()
}
render(){
return(
<div className='link-container'>
<Link to='Something' onClick={e => this._onClick(e)}
</div>
)
}
}
Just making the URL null seems to do the trick:
const url = isDisabled ? null : 'http://www.stackoverflow.com';
return (
<a href={url}>Click Me</a>
);
In short easier way to disable link in React?
<Link to="#">Text</Link>
I think you should you atrribute to=null to set disable a link.
<Link to=null />
Your code:
render() {
return (<li>
<Link to={this.props.canClick?'/goto-a-link':null} >Test</Link>
</li>)
}
Passing # in to prop to the Link should do the trick for you
You can define link as per your requirement. if you want to disable it just pass # in props.link
render() {
return (<li><Link to={props.link}>Test</Link></li>);
}
I didn't like any of the answers. Surprisingly, if you are using bootstrap, assigning the class disabled will make the link inactive. So, no need to change the path to # or anything.
<Link to='something/else' className='nav-link disabled'>Transactions Detail</Link>
Use this in your link tag. I'm using it in functional component and it's working fine.
<Link style={{pointerEvents: 'none'}}>
You can conditionally set the to prop of the Link component. When you set it to #, the link would be disabled.
render() {
return (
<li>
{
<Link to={`${this.props.canClick ? '/' : '#'}`}>Test</Link>
}
</li>
)
}

Categories