I have a menu in my React app, here's the Menu component:
class Menu extends React.Component {
constructor(props) {
super(props);
this.state = {
active: '/'
}
}
render() {
return (
<nav>
<ul className='list-inline'>
<li>
<Link to='/' style={this.state.active === '/' ? activeStyle : {}} onClick={this.handleClick.bind(this, '/')}>
Home
</Link>
</li>
<li>
<Link to='/contact' style={this.state.active === 'contact' ? activeStyle : {}} onClick={this.handleClick.bind(this, 'contact')}>
Contact
</Link>
</li>
)
}
}
export default Menu
When I click on a menu item, the clicked item will get higlighted (bold). But if I have in the URL some page (eg. http://localhost:3001/contact) and refresh the page, this Contact item in the menu will not be highlighted (because highlighting is made based on the onClick event).
I tried to parse the content of URL with import * as qs from 'query-string'; // for fetching the URL paramaters and then I tried to display the URL content:
console.log(qs.parse(location.search));
But the output is only {} instead of the desired contact (so I could highlight this item in the menu).
Thus, when a URL is loaded straight (without click on the respective menu item), how do I catch this situation and highlight the respective menu item?
Thank you
React router has a component for exactly this situation
https://reacttraining.com/react-router/web/api/NavLink
You can change the component from Link to NavLink and add the component will check the url in which you are.
<Link to='/contact' style={this.state.active === 'contact' ? activeStyle : {}} onClick={this.handleClick.bind(this, 'contact')}>
Contact
</Link>
<NavLink
to="/contact"
activeStyle={activeStyle}
>Contact</NavLink>
Also, you can check the URL params from the router instance:
https://reacttraining.com/react-router/web/example/url-params
Related
I'm sorry if my question has already asked.
I am a beginner on react and I really want to learn how to do this and understand.
I use Firebase on my React.JS project and i want switch a part of header when the user has connected or not.
I think using the conditional-rendering but on the firebase function after the (if) does not allow me to do setState().. or i have an error
So I would be very happy if we could help me or give me a track of where to look for the answers !
class Header extends Component {
state={
connected: null
}
render(){
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
} else {
}
});
return (
<div className="backgroundheader">
<div className="liensheader">
<a href="/" className="lili" style={{textDecoration: "none"}}>Home</a>
<a href="/event" className="lili" style={{textDecoration: "none"}}>Manifestations</a>
<a href="/commerces" className="lili" style={{textDecoration: "none"}}>Commerces</a>
<a href="/tips" className="lili" style={{textDecoration: "none"}}>Tips</a>
</div>
{/* options header when the user is disconnect */}
{/* <Deader /> */}
{/* options header when the user is connected */}
{/* <Ceader /> */}
</div>
);
}
};
export default Header;
Thank's you and sorry for my bad english :/
The onAuthStateChanged fires asynchronously, so you can't directly use it inside your render method. Whenever you have a situation like this, the solution is to put the asynchronous value into the state, and then use the state in the render method.
So something like:
class Header extends Component {
state={
connected: null
}
componentDidMount() {
firebase.auth().onAuthStateChanged(function(user) {
setState({ user: user });
});
}
render(){
return (
<div className="backgroundheader">
<div className="liensheader">
<a href="/" className="lili" style={{textDecoration: "none"}}>Home</a>
<a href="/event" className="lili" style={{textDecoration: "none"}}>Manifestations</a>
<a href="/commerces" className="lili" style={{textDecoration: "none"}}>Commerces</a>
<a href="/tips" className="lili" style={{textDecoration: "none"}}>Tips</a>
</div>
{ user ? <Deader /> : <Ceader /> }
</div>
);
}
};
export default Header;
Also see:
Firebase storage: download images to and put to img src in React map. The same problem of asynchronously loaded data, but then with getting the download URL of images in Cloud Storage.
How to update Firebase data to the React application in realtime. This highlights the same problem of asynchronously loaded data, but now with getting JSON data from the Realtime Database.
The following React.js code renders a navbar with two links named 'about' and 'project'. On page load the 'about' link is active and colored red. When the other link is clicked the state of the navbar is set to 'project', 'about' link style is set back, and 'project' is colored red.
I achieve this by attaching a click handler to both link tags, and set the state of active to the name of the event.target.innerHTML.
I'm new to react, and I feel this is a really verbose way of going about this. I am aware that there is an activeClassName prop you can pass to a react-router link, but I want a way that does not use it.
import React, { Component } from 'react'
import { Link, Route } from 'react-router'
export default class Navbar extends Component {
constructor() {
super();
this.state = {
active: 'about'
}
this._handleClick = this._handleClick.bind(this);
}
_handleClick(e) {
this.setState({
active: e.target.innerHTML
});
}
render() {
let aboutStyle;
let projectStyle;
if (this.state.active === 'about') {
aboutStyle = { color: '#ff3333' };
projectStyle = {};
} else {
aboutStyle = {};
projectStyle = { color: '#ff3333' };
}
return (
<div className='navbar'>
<Link to='/'><h2>BK //</h2></Link>
<div className='menu'>
<Link style={aboutStyle} onClick={this._handleClick} to='about'>about</Link>
<Link style={projectStyle} onClick={this._handleClick} to='projects'>projects</Link>
</div>
</div>
)
}
}
At this day you can use NavLink from react-router-dom. This object supports attributes as activeClassName, activeStyle, or isActive (for functions).
import { NavLink } from 'react-router-dom';
<NavLink to='about' activeClassName="active">about</NavLink>
// Or specifing active style
<NavLink to='about' activeStyle={{color: "red"}}>about</NavLink>
// If you use deep routes and you need an exact match
<NavLink exact to='about/subpath' activeClassName="active">about</NavLink>
For more options read documentation: https://reacttraining.com/react-router/web/api/NavLink
maybe slightly less verbose... in Pseudocode
const menuItems = [
'projects',
'about',
];
class MenuExample extends React.Component {
_handleClick(menuItem) {
this.setState({ active: menuItem });
}
render () {
const activeStyle = { color: '#ff3333' };
return (
<div className='menu'>
{menuItems.map(menuItem =>
<Link
style={this.state.active === menuItem ? activeStyle : {}}
onClick={this._handleClick.bind(this, menuItem)}
>
{menuItem}
</Link>
)}
</div>
);
}
}
Using NavLink in place of Link gives you the opportunity to set your preferred style for the active page/link.
So you can go ahead and set the style in CSS like this.
.active {
color: 'red'
}
We can use NavLink to highlight the active by writing custom class handling based on de-structured isActive property
<NavLink
to='/'
className={
useCallback(({isActive}) => isActive ? classes.active : classes.link)}
>
Home
</NavLink>
Ref: https://stackoverflow.com/a/72520423/4652706
As of React Router v6, activeClassName prop will not work. Find the solution here, ReactJS - Unknown prop `activeClassName` on <a> tag. Remove this prop from the element
Have a component that's display menus from array
import React from 'react'
import { Link, browserHistory,IndexLink } from 'react-router'
$( document ).ready(function() {
$( "ul.tabs li a" ).first().addClass("current");
$("li:not(:first-child)").click(function() {
$( "ul.tabs li a" ).first().removeClass("current");
});
});
function Tabs (props) {
const numbers = props.menuitems;
const listItems = numbers.map((number) =>
<li key={number.link} ><Link to={number.link} activeClassName="current" className="tab-link">{number.linkName}</Link></li>
);
return (
<div>
<ul className="tabs" >{listItems}</ul>
<div className="tabs-header-stripe"></div>
</div>
);
}
export default Tabs
I added "curent" class by Jquery to first element, the problem is When I go from another page, class not adding, but when I just refresh page It's add normaly.
What you say is happening because the class is added in documentReady event. When yo arrive from another page the event has already been raised but of course the following code cannot find the dom element because it is not present in the page:
$( "ul.tabs li a" ).first()
What I can suggest is to avoid using jquery (and modifying the dom from outside react) and add the class directly in the react code.
I guess you wanted to do something like this:
import React from 'react'
import { Link, browserHistory,IndexLink } from 'react-router'
function Tabs (props) {
const numbers = props.menuitems;
const listItems = numbers.map((number, index) =>
<li key={number.link} ><Link to={number.link} activeClassName="current" className={index === 0 ? "tab-link current" : "tab-link"}>{number.linkName}</Link></li>
);
return (
<div>
<ul className="tabs" >{listItems}</ul>
<div className="tabs-header-stripe"></div>
</div>
);
}
export default Tabs
I'm using React Router v4 and trying to write up a wrapper that allows the Bootstrap dropdown class to be active. The gist is that I need match multiple routes, and I'm unsure exactly how to do that in this wrapper.
Here is what I have:
import React, { PropTypes } from 'react';
import { Link } from 'react-router';
const DropDownLinkWrapper = ({links, label}) => {
return (
<Link to="/link1|/link2"> // <-- this is what I want to do
{({isActive}) =>
<li className={`dropdown ${isActive ? 'active' : ''}`}>
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">{label}<span className="caret"/></a>
<ul className="dropdown-menu">
{// output menu links here}
</ul>
</li>
}
</Link>
);
};
DropDownLinkWrapper.propTypes = {
links: PropTypes.array.isRequired,
label: PropTypes.string.isRequired
};
export default DropDownLinkWrapper;
I would imagine that the first <Link/>'s to prop would need to match on two URLs. But of course, this doesn't work. Does anyone have a solution for this?
Using React-Router's Link, I have a set up like so:
<Link to={...}>{this.props.live? "Live": "Not Live"}</Link>
Where if this.props.live gets passed in, I would like to simply display a text "Live" which will direct to a new page. If this.props.live is not passed in, want to display the text "Not Live" but remove the hyperlink from it/deactivate/disable it.
Is it possible to do so? I tried <div style={{pointerEvents: "none"}}>Not Live</div>, but does not work.
Will be upvoting and accepting answer. Thank you!
You should do this:
let component;
component=this.props.live? <Link to={...}> Live </Link>: <div> Not Live </div>
render() {
{component}
}
Cheers:)
this.props.live
? <Link to={...}> Live </Link>
: <div> Not Live </div>
You can prevent the page to be redirected using evt.preventDefault()
class MyComponent extends React.Component {
constructor(props) {
this.handleLinkClick = this.handleLinkClick.bind(this);
}
handleLinkClick(evt) {
if (!this.props.live) {
evt.preventDefault(); // will prevent redirection
}
}
render() {
<Link onClick={this.handleLinkClick} to={...}>
{this.props.live? "Live": "Not Live"}
</Link>
}
}
Shorthand but controversial version
<Link onClick={evt => !this.props.live && evt.preventDefault()} to={...}>
{this.props.live? "Live": "Not Live"}
</Link>
See the API docs