v4 build 0.7 seems to have had issues on my NavLinks, where the activeClassName is not updating when the url changes.
This simply makes the navigation background not change when a page is changed. If I refresh the entire window, the correct nav is active, however the class name does not seem to be updating.
````
````
Are you using a component that implements shouldComponentUpdate
between your router an d your navlinks?
No just a standard component with links
````import React, { Component } from 'react';
import { NavLink } from 'react-router-dom';
import './Nav.scss'
class Nav extends Component {
render() {
return (
<nav>
<ul>
<li>
<NavLink to="/" exact activeClassName="active" ><span className="fa fa-home"></span>
<span className="title">Home</span>
</NavLink>
</li>
<li>
<NavLink to="/search" activeClassName="active"><span className="fa fa-search"></span>
<span className="title">Search</span>
</NavLink>
</li>
<li>
<NavLink to="/fav" activeClassName="active"><span className="fa fa-star"></span>
<span className="title">Favourites</span>
</NavLink>
</li>
<li>
<NavLink to="/history" activeClassName="active"><span className="fa fa-history"></span>
<span className="title">History</span>
</NavLink>
</li>
<li>
<NavLink to="/admin" activeClassName="active"><span className="fa fa-cogs"></span>
<span className="title">Admin</span>
</NavLink>
</li>
</ul>
</nav>
);
}
}
export default Nav;````
I think this might be related - I'm also having an issue when the build went from 0.6 to 0.7. When I click on a NavLink
, the URL changes in top bar, but the components dont switch at all. This is without any code changes, it just seems to be an issue when I switch versions. My Nav
is similar to the one above.
Can you verify that the <NavLink>
s are re-rendering? Even if you aren't calling sCU
directly, you might have third-party code that is calling it (like connect
or observable
).
I put together a simple codepen where this is working.
I am running the parent component in a mobx decorator. It calls the Nav. Not sure if that has an effect
````
import React, {Component} from 'react';
import './Header.scss';
import { Link } from 'react-router-dom';
import { observer } from "mobx-react"
import Nav from './Nav';
import User from './User';
import logo from '../logo.png'
@observer } export default Header; My Root component is also wrapped in an observer ```` } Yes. I also had the same issue when I tried upgrading to beta 7. Any routes withing a component which was using the react-redux connect HOC (which implements shouldComponentUpdate) would not update. Is the long term solution to this going to be passing the location prop or is this just a temporary work-around until this gets solved? @nzjoel1234 Any As mentioned before, is this a temporary change, or long term, as it was quite intuitive that NavLink would automatically update itself regardless pre-beta7? This means each time I create a NavLink now, I will need to make sure its additionally passes a location prop all the way down the components, (depending on how deep it is). Your I apologies to ask again, but I just want to be a bit more clear. In my example above, the root App component calls the Header, which calls the Nav. I am unsure where I am getting this location prop from, and am I passing it from App > Header to Nav, and never even using it? I previously felt comfortable knowing that no matter where I place a Link (now NavLink) as long as the to=url, isActive would work, and automatically update activeClassName. However now I can't get head around what is happening differently, before and now, as to those automatic updates no longer happening and now a manual process. I would much rather re-create a new NavLink component which worked as it previously did. Pretend for a minute that If that were the case, then a component that implements Back to reality, where The solution is thus to pass the You can read more about this and how to access the @pshrmn Since most people who will get this issue are using either Redux of Mobx would it be possible for react router to allow some type of middleware which could be used to provide a way of sharing state instead of using context? So on Hope this makes sense? Interesting... I found this issue with my By changing to That's because the PureComponent blocks the update to the components underneath it: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md I fixed my own problem awhile ago, but this was indeed the issue with me (I was using I had to add a I'm on v4.1.1 of I have a class I do not know how to proceed, I tried using context but did not do much for me. Any suggestions ? @ryanhomer I've tried your solution, added @PDS42 No, that's all I had to do. However, as an alternative and cleaner solution, I ended up wrapping my components using Hope this helps. Unfortunately I already did that, and it did not help (pretty sure you cannot pass the location prop without withRouter anyway?). If you think of anything else please let me know! Thank you for taking the time. I had the same issue with router, but solution proposed by @ryanhomer helped (wrap component with "withRouter ") Thank you, sir! :+1: @PDS42 If you are using @ryanhomer I just realized I actually did not wrap the parent component, but just the one with the I had the same and wrapping my App component into withRouter did help. Same here. Just wrapped the parent component withRouter and it worked. I was having this problem and my entire App was already wrapped using I'm not actually using component wrapped in connect becoming Pure, if 4th argument passed connect Pure components does not provide context to their children, and 2017-10-18 5:36 GMT+08:00 rokit notifications@github.com: I was having this problem and my entire App was already wrapped using const mapStateToProps = (state) => { I'm not actually using router anywhere in my component, but just adding — As @zaynv mentioned, passing the and then in the Navigation component where it holds the I setup codesandbox demo and I can't get active links to work: https://codesandbox.io/s/m36091p4yp Damn, weird. The solutions work in one of my apps, but don't in other. Weird 😞 @stas-dolgachov 's answer worked for me (whew!). I now have much smaller problem, hopefully someone here can jumpstart me. My export is using compose: How can rewrite this to have the "withRouter" in the right place? I am weary, begging a handout :) @lgerndt pretty sure you just have to do this: Let me know if that worked!
class Header extends Component {
render() {
return (
GPbook
</Link>
<Nav />
<User />
</header>
);
}
````
@observer
class App extends Component {
render() {
return (
{store.user ?
</div>
</Router>
</Provider>
);
}
````observer
calls shouldComponentUpdate
. Only observers that are children of the <Router>
will need to pass the location prop.sCU
call should return true
when the location changes. Passing the location
as a prop will do this, but it already isn't an issue if other props are changing (e.g. you are passing in product props from the store in your mapStateToProps
based on a URL param). There are also plans to remove sCU
from react-redux
. If you really don't want to use a location prop, you can pass the { pure: false }
option to connect
.<NavLink>
doesn't need to be passed the location. It is whatever component is calling sCU
that needs the location so that it knows that it should allow a re-render when the current and next location
props are different.context
does not exist. If that is the case, then the only way to pass routing information to children components would be through props. Each child would receive the current location
as well as other props from its parent.shouldComponentUpdate
(returning true
if a shallow check of its props shows that at least one of them updated) would re-render whenever the location
prop changes. That is how mobx-react
's observer
implements sCU
.context
does exist as a way to pass state. You navigate, the location
object changes, and the above component that implements sCU
runs. However, now that location
is part of the context
, sCU
does not detect that the location
object is different and it returns false
, preventing it and its children from updating. When this is happening we do want to update, the problem is just that there isn't a good way for sCU
to detect this (at least when using third-party components).location
as a prop to the component that implements sCU
.location
in the dealing with updating blocking guide.history.onChange
react router could call something like middleware.setNewLocation(location)
if no custom middleware was provided then this would update the context otherwise some custom middleware could store the new location in Redux state for example. Then the withRouter
HOC could retrieve location etc. from the middleware, and Links etc. could also use withRouter
to get their props?NavBar
component. I'm using redux, but I don't have any connect
between the router and the NavLinks. The problem I had, it was because I was extending from PureComponent
class NavBar extends PureComponent {
//...
}
Component
the active class started working.class NavBar extends Component {
// ...
}
redux-form
. Passing the Form
component the location
prop made things work again. Thanks for the great docs!pathname
property to the component in which I was using the NavLink
and make sure it was getting the current pathname
from the location
property passed down by the Route
component. This causes the component to re-render when the pathname changes (even if you are not directly using the pathname
property) and allows the NavLink
component to update.react-router
and react-router-dom
, and getting the same issue. If I got all the above right, I should look for a way to let NavLink
know that it should update and render again. class MenuListItem extends Component {...}
, and inside multiple elements, including <NavLink strict={true} to={this.props.url} className={${styles.container} ${styles.link}} activeClassName={styles.linkActive}>
. pathname
prop (passing this.props.location.pathname
) to my MenuListItem
component, and it changed nothing. Is there any step you did not detail in your explanation that can make it work for me ? withRouter
. In my case, I have a main component in which the routing takes place and which renders Component1 which in turn renders Component2. I had to wrap both Component1 and Component2 in order for the re-render to work. So, something like this.import { withRouter } from 'react-router-dom';
class Component1 extends React.Component { render() {} };
Component1 = withRouter(Component1);
export default Component1;
How it works for me:
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CategoriesMenu));
CategoriesMenu - contains other components with NavLinks and activeClassNamewithRouter
and connect
together, it has to be done like how @stas-dolgachov did it, withRouter
wrapping connect
.withRouter
did the trick for me. Thank you! :)withRouter
. I'm also using Redux. I noticed that it would style the correct link if I manually refreshed the page on any given route which made me think of mapping router to props to trigger an update:const mapStateToProps = (state) => {
return {
router: state.router,
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)
router
anywhere in my component, but just adding that in made the active style work.
does not declare opposite.export default connect(mapStateToProps, mapDispatchToProps, mergeProps, {
true: false })
react-router hugely depends on context.
withRouter. I'm also using Redux. I noticed that it would style the
correct link if I manually refreshed the page on any given route which made
me think of mapping router to props to trigger an update:
return {
router: state.router,
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)
that in made the active style work.
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/ReactTraining/react-router/issues/4638#issuecomment-337379306,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACJseS9FCX7jPFZdwLfiXCyfp0YrnuN8ks5stR3YgaJpZM4MTapo
.location
as a prop
to the component holding the NavLink
will make active class work again.
In my case I had to get location
using withRouter
:class App extends React.Component{
render() {
const { location } = this.props
return(
<div id="AppWrap">
<Navigation location={location}/>
<Route exact path="/" component={Home}/>
</div>)
}
}
export default withRouter(App)
NavLinks
simply started setting active classes again.export default compose(
connect(mapStateToProps, mapDispatchToProps),
withStyles(styles, { name: 'App' }),
withTheme(),
)(Header);
export default compose(
withRouter,
connect(mapStateToProps, mapDispatchToProps),
withStyles(styles, { name: 'App' }),
withTheme(),
)(Header);
Most helpful comment
I had the same issue with router, but solution proposed by @ryanhomer helped (wrap component with "withRouter ")
How it works for me:
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(CategoriesMenu));
CategoriesMenu - contains other components with NavLinks and activeClassName
Thank you, sir! :+1: