React throws Warnings when nesting NavLink - reactjs

I am trying to use NavLink to build a navigation menu and I am using NavLink to implement it because of the activeClassName property.
But when I try to nest them together, to make a Drop Down Menu, warnings show up at Chrome Debugger.
Warning: validateDOMNesting(...): <a> cannot appear as a descendant of <a>.
Is there any way to remove such warnings during development, or is there any better approach for creating NavBar while keeping activeClassName style?
Thanks.
<NavLink to="/dashboard" activeClassName="Activated">
<div className="dropdown">
<label>Items</label>
<div className="dropdown-content">
<NavLink exact to="/dashboard/Item1" activeClassName="Activated">
Item1
</NavLink>
<NavLink exact to="/dashboard/Item2" activeClassName="Activated">
Item2
</NavLink>
<NavLink exact to="/dashboard/Item3" activeClassName="Activated">
Item3
</NavLink>
</div>
</div>
</NavLink>
Edited on 2019-02-20
I have created a CodePen based on the answer from #JupiterAmy, but did not see what expected, can you(or someone) do some modification?
CodePen Link

Navlink components returns an anchor tag itself. You can see that yourself in devtools. That's the reason you are getting this error. For nested links, you should take advantage of react router dynamic routing which was introduced in v4.
To achieve this, you should have a parent component which will have the Navlink which contains the link to your Homepage. something like this.
const Parent = () => {
return (
<div>
<NavLink
to="/dashboard"
activeClassName="Activated">
GoToDashboard
</NavLink>
</div>
);
}
Now in your dashboard component you should have your nested links.
const Dashboard = () => {
return (
<div className="dropdown-content">
<NavLink exact to=`${match.url}/item1` activeClassName="Activated">
Item1
</NavLink>
<NavLink exact to=`${match.url}/item2` activeClassName="Activated">
Item2
</NavLink>
<NavLink exact to=`${match.url}/item3` activeClassName="Activated">
Item3
</NavLink>
</div>
);
}
Now, when you click this Links from inside of Dashboard component, you will get the links as expected.
/dashboard/item..

Check out the below code and image for your reference.
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Switch, Route, NavLink } from 'react-router-dom';
const Root = () => {
return (
<BrowserRouter>
<Parent />
</BrowserRouter>
);
};
const Parent = () => {
return (
<div>
<NavLink className="dropdown"
to="/dashboard"
activeClassName="Activated">
GoToDashboard
</NavLink>
<Route path="/dashboard" component={Dashboard} />
</div>
);
}
const Dashboard = () => {
return (
<div className="dropdown-content">
<NavLink to="/dashboard/item1" activeClassName="Activated">
Item1
</NavLink>
<NavLink to="/dashboard/item2" activeClassName="Activated">
Item2
</NavLink>
<NavLink to="/dashboard/item3" activeClassName="Activated">
Item3
</NavLink>
<Route path="/dashboard/item1" component={Item1} />
<Route path="/dashboard/item2" component={Item2} />
<Route path="/dashboard/item3" component={Item3} />
</div>
);
}
const Item1 = () => {
return (
<div>
<h1>Item1</h1>
</div>
);
}
const Item2 = () => {
return (
<div>
<h1>Item2</h1>
</div>
);
}
const Item3 = () => {
return (
<div>
<h1>Item3</h1>
</div>
);
}
ReactDOM.render(<Root />, document.getElementById('app'));
For some reason, I wasn't able to get the same run in a codepen. You can try to run the code in your local set up. It works and I hope serves your purpose.

Related

Passing props through NavLink

I am trying to pass props from NavLink in react-router-dom to another component (component that router routes to). The code is:
<HashRouter>
<div className="navigation">
<NavLink to="/" className="navigation-link">Home</NavLink>
<NavLink quizid="60fcf0f3b55bab18d841e4c3" className="navigation-link"
to={{
pathname:'/thisquiz',
state: "60fcf0f3b55bab18d841e4c3"
}} exact>Quiz</NavLink>
</div>
<div>
<Route default exact path="/" component={Home}></Route>
<Route path="/thisquiz" component={Quiz}></Route>
</div>
</HashRouter>
In the Quiz component:
let location = useLocation();
console.log("The state is "+location.state);
The output shows The state is undefined. Please help.
Try
<NavLink quizid="60fcf0f3b55bab18d841e4c3" className="navigation-link"
to={{
pathname:'/thisquiz',
id: { id: "60fcf0f3b55bab18d841e4c3" }
}}
exact
>
Quiz
</NavLink>
then
const Quiz(props) => {
console.log(props.location.id);
return (
// code here
)
}
Also, would be good if you change your div tag on <div className="navigation"> for a <nav> tag.
https://medium.com/#bopaiahmd.mca/how-to-pass-props-using-link-and-navlink-in-react-router-v4-75dc1d9507b4

Getting bugs in Routing in React

I am having a unusual problem in my routing. I have a home page and then in the mid level of the home page, I have a link of my about page. When I click on that in redirects me to the mid level of the about page. Why it is not taking me to the top level of the about page. I think I have scrolled in home page cause it has also scrolled in the about page I don't know it is a very weird problem .I am providing my nav items and all my Links' code here. Please give me a solution if you can.
import React, { Component } from 'react'
import { BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import Nav from './Components/Nav'
import Home from './Components/Home'
import About from './Components/About'
import Project from './Components/Project'
import Skills from './Components/Skills'
import Services from './Components/Services'
import Contact from './Components/Contact'
const App = () => {
return (
<>
<BrowserRouter>
<Nav />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/service" component={Services} />
<Route path="/project" component={Project} />
<Route path="/skill" component={Skills} />
<Route path="/contact" component={Contact} />
<Redirect to="/" />
</Switch>
</BrowserRouter>
</>
)
}
export default App
import React, { useState } from 'react'
import { NavLink, Link } from 'react-router-dom'
import Mode from './Mode'
import Button from '#material-ui/core/Button'
const Nav = () => {
const [icon, setIcon] = useState(false)
const [open, setClose] = useState(false)
function Nav() {
document.querySelector('#NavLinks').style.transform = 'scaleX(1)'
setClose(!open)
setIcon(!icon)
}
function NavClose() {
document.querySelector('#NavLinks').style.transform = 'scaleX(0)'
setClose(!open)
setIcon(!icon)
}
return (
<>
<nav data-aos="fade-in">
<div id="Container">
<div id="NavContentWrapper">
<h2 id="NavTitle">
<Link to="/">DevR</Link>
</h2>
<ul id="NavLinks">
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/about">
About
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/service">
Service
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/project">
Projects
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/skill">
Skills
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
<li>
<Mode />
</li>
</ul>
<div id="Bar">
<Button
variant="outlined"
color="primary"
onClick={open ? NavClose : Nav}
>
{icon ? (
<i className="fas fa-times"></i>
) : (
<i className="fas fa-bars"></i>
)}
</Button>
</div>
</div>
</div>
</nav>
</>
)
}
export default Nav
Add this to your App component:
const location = useLocation();
useLayoutEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);

Nested "Redirect" in React-Router-DOM

I'm new to React JS and now I'm trying to learn how to use "react-router-dom". Here I have a very simple app and I'm trying to fix one issue. So, there are 4 pages (Main Page / First Page / Second Page / Third Page wih Items ). We can ignore the first 3 pages and focus on the last one - Third Page wih Items. There we have 3 items. I used <Redirect /> to make First Item content visible immediately after users click on Third Page wih Items and it seems to work fine but there is a problem... First time you click on Third Page wih Items, First Item is shown as expected. But if you are still inside Third Page wih Items and you click on it again, First Item disappears and you basically need to reload the page or go to another page and back.
My question is - What should I do make First Item stays even if users click on Third Page wih Items multiple times in a row?
import React from "react";
import { Route, NavLink, Redirect } from "react-router-dom";
import "./App.css";
const Header = () => {
return (
<ul>
<li>
<NavLink to="/">Main Page</NavLink>
</li>
<li>
<NavLink to="/first">First Page</NavLink>
</li>
<li>
<NavLink to="/second">Second Page</NavLink>
</li>
<li>
<NavLink to="/third-with-items">Third Page wih Items</NavLink>
</li>
</ul>
);
};
const Main = () => <h1>Main Page</h1>;
const First = () => {
return <h3>First Page Content</h3>;
};
const Second = () => {
return <h3>Second Page Content</h3>;
};
const Third = () => {
return (
<div>
<div>
<h3>Third Page Content</h3>
<ul>
<li>
<NavLink to="/third-with-items/item1">First Item</NavLink>
</li>
<li>
<NavLink to="/third-with-items/item2">Second Item</NavLink>
</li>
<li>
<NavLink to="/third-with-items/item3">Third Item</NavLink>
</li>
</ul>
</div>
<Redirect to="/third-with-items/item1" />
<Route path="/third-with-items/item1" component={FirstItem} />
<Route path="/third-with-items/item2" component={SecondItem} />
<Route path="/third-with-items/item3" component={ThirdItem} />
</div>
);
};
const FirstItem = () => (
<div>This text should be shown after you click "Third Page with Items"</div>
);
const SecondItem = () => <div>Something...</div>;
const ThirdItem = () => <div>Another something...</div>;
const App = () => {
return (
<div>
<Header />
<Route exact path="/" component={Main} />
<Route path="/first" component={First} />
<Route path="/second" component={Second} />
<Route path="/third-with-items" component={Third} />
</div>
);
}
export default App;
Replace:
<Redirect to="/third-with-items/item1" />
with:
<Route exact path="/third-with-items" component={FirstItem} />
The React Router documentation shows an example of nesting routes that may help you improve your component:
import {BrowserRouter, Route, NavLink, Switch, useRouteMatch} from "react-router-dom";
const Third = () => {
let { path, url } = useRouteMatch();
return (
<div>
<div>
<h3>Third Page Content</h3>
<ul>
<li>
<NavLink to={`${url}/item1`}>First Item</NavLink>
</li>
<li>
<NavLink to={`${url}/item2`}>Second Item</NavLink>
</li>
<li>
<NavLink to={`${url}/item3`}>Third Item</NavLink>
</li>
</ul>
</div>
<Switch>
<Route exact path={path} component={FirstItem} />
<Route path={`${path}/item1`} component={FirstItem} />
<Route path={`${path}/item2`} component={SecondItem} />
<Route path={`${path}/item3`} component={ThirdItem} />
</Switch>
</div>
);
};

React Router 5.1 - useLocation hook - determine past locations

According to React Router 5.1 documentation it should be possible to see "where the app is now, where you want it to go, or even where it was". In my app I need to see "where it was" - what locations I have visited before landing at a specific location.
More precisely; I wish to find a prevoious location matching a certain pattern. That location might be two or three locations ago.
However - I cannot figure out how to perform this.
What is the best and recommended approach to achieve this?
Kind regards /K
I turns out the best way, for me, to see where the application has been been is to simply use the state property in the React Router Link.
This article on how to pass state from Link to components really helped explain how to use the Link state.
Basically the Link can pass the state property to the rendered component.
<Link to={{ pathname: "/courses", state: { fromDashboard: true } }} />
The rendered component then access the state via props.location.state
This in conjunction with passing props to components generating the links solved my problem! (^__^)
In React Router you can use the goBack() method if you need to react a previous path in your history. Also, there is a possibility to push your path to history state, but that’s only needed if you need to know the URL of the previous location.
You can read more about this functionality from here: https://reacttraining.com/react-router/web/api/history
You can check this example. Hope it helps you.
import React from "react";
import {BrowserRouter as Router,Switch,Route,Link} from "react-router-dom";
import { withRouter } from "react-router";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
const About = withRouter(({history, ...props}) => (
<h1 {...props}>
About
<hr/>
<button onClick={() => {history.push('/')}}>go back</button>
</h1>
));
Another Example for going back -2
import React from "react";
import {BrowserRouter as Router, Switch, Route, Link} from "react-router-dom";
import {withRouter} from "react-router";
export default function BasicExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/about/insideabout">Inside About</Link>
</li>
</ul>
<hr/>
<Switch>
<Route exact path="/">
<Home/>
</Route>
<Route exact path="/about">
<About/>
</Route>
<Route path="/about/insideabout">
<InsideAbout/>
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
const About = withRouter(({history, ...props}) => (
<div>
<h1>
About
<hr/>
<button onClick={() => {
// history.push('/')
history.goBack(-1);
}}>go back
</button>
</h1>
</div>
));
const InsideAbout = withRouter(({history, ...props}) => (
<h1 {...props}>
Inside About
<hr/>
<button onClick={() => {
history.goBack();
}}>go back
</button>
<button onClick={() => {
history.go(-2);
}}>go home
</button>
</h1>
));

ReactJS - Unknown prop `activeClassName` on <a> tag. Remove this prop from the element

I am using react 15.4.2 and react-router4.0.0 and This project was bootstrapped with Create React App.
Here is my Code.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import {BrowserRouter as Router,Route,Link} from 'react-router-dom'
const AboutPage = () => {
return(
<section>
<h2>This is About page</h2>
<Link activeClassName="active" to="/about/nestedone">Nestedone</Link>
{' '}
<Link activeClassName="active" to="/about/nestedtwo">Nested two</Link>
</section>
)
}
const HomePage = () => {
return(
<section>
<h2>This is Home page</h2>
<Link to="/about">About</Link>
</section>
)
}
const NestedOne = () => {
return (
<section>
<h2>Nested page 1</h2>
</section>
)
}
const NestedTwo = () => {
return (
<section>
<h2>Nested page 2</h2>
</section>
)
}
ReactDOM.render(
<Router>
<section>
<Route exact path="/" component={HomePage} />
<Route path="/about" component={AboutPage} />
<Route path="/about/nestedone" component={NestedOne} />
<Route path="/about/nestedtwo" component={NestedTwo} />
</section>
</Router>,
document.getElementById('root')
);
When I browse /about, I am getting this error:
"Warning: Unknown prop activeClassName on tag. Remove this prop from the element.
What am I doing wrong here?
Thanks!
From v6 onwards of react-router replace activeClassName with className and use navData.isActive to toggle style.
Old way:
<NavLink to="/home" activeClassName="active-style">Home</NavLink>
v6 onwards:
<NavLink to="/home" className={(navData) => (navData.isActive ? "active-style" : 'none')}>Home</NavLink>
or you can also destructure isActive from navData:
<NavLink to="/home" className={({isActive}) => (isActive ? "active-style" : 'none')}>Home</NavLink>
The activeClassName property is not a property of Link but of NavLink.
So, just change your code to use NavLink instead of Link:
const AboutPage = () => {
return(
<section>
<h2>This is About page</h2>
<NavLink activeClassName="active" to="/about/nestedone">Nestedone</NavLink>
{' '}
<NavLink activeClassName="active" to="/about/nestedtwo">Nested two</NavLink>
</section>
)
Remember to import the NavLink from the react-router-dom:
import { NavLink } from 'react-router-dom'
In React Router v6 activeClassName has been changed to just className where a prop isActive can be used to manipulate the styling.
For more info
https://reactrouter.com/docs/en/v6/upgrading/v5#remove-activeclassname-and-activestyle-props-from-navlink-
const AboutPage = () => {
return(
<section>
<h2>This is About page</h2>
<NavLink className={({ isActive }) => isActive? "active": ''} to="/about/nestedone">Nestedone</NavLink>
{' '}
<NavLink className={({ isActive }) => isActive? "active": ''} to="/about/nestedtwo">Nested two</NavLink>
</section>
)
}
activeClassName is not a property of Link but of NavLink.
Since react-router v4 beta8, the property is active by default. Verify which version is installed in your node modules folder
My issue was that I was using reactstrap and importing their NavLink element which does NOT have the attribute activeClassName. Make sure you import NavLink from the react-router library like this:
import { NavLink } from 'react-router-dom'
Using activeclassname instead of activeClassName fixed it for me, like so:
<NavLink to="/home" activeclassname="active">Home</NavLink>

Resources