react-router: ActiveState changes don't propagate if any single parent in hierarchy declares shouldComponentUpdate
If I have a component using ActiveState
mixin and some of its parents declare shouldComponentUpdate
, the child won’t update when active state changes.
This is not normal because usually parent’s shouldComponentUpdate
doesn’t magically cut the child off updates. If child listens to some store and calls setState
, it will be updated. But this is not the case with context
.
Even if parent’s shouldComponentUpdate
implementation takes nextContext
into account, it won’t even get nextContext
if it doesn’t declare contextTypes
itself. So basically, for ActiveState
to work in a project that heavily uses shallow-comparing shouldComponentUpdate
or something similar, all ancestors of ActiveState
-using component need to also have ActiveState
.
See this React issue and this fiddle.
Obviously it’s a React’s problem per se but since router relies on context so much, it’s worth documenting.
About this issue
- Original URL
- State: closed
- Created 10 years ago
- Comments: 87 (80 by maintainers)
Commits related to this issue
- Make <Link> work with static containers Fixes #470 — committed to gaearon/react-router by gaearon 8 years ago
- Add failing test for #470 — committed to gaearon/react-router by gaearon 8 years ago
For anyone who’s already using React Router Redux, I made a pretty simple
Link
component and it’s working on two apps I’m working on:Btw, it can replace both
Link
andIndexLink
components.Actually, better implementation:
Thanks for chiming in! It will be great when React solves that.
But right now people do extreme things (that’s a base Component class for the whole framework!) just to get around the issue, and many aren’t even aware that the issue exists.
It’s easy to fix on the router level. Let
_subscribe
be a private API for now if we don’t want people to depend on it. When React solves this, we can bump the minimum version and remove the hack.I really want RR 1.0 to fix this, and if it comes out before React fixes sCU with context, I’d vote for doing a sideways subscription.
This is now out in
3.0.0-alpha.1
. Please give it a try!@gaearon Yeah, I know. And it also changes the activeClassName before animations, but at least it’s a fallback until this is solved “natively” in react-router. Same to your
gist
, but probably in a more performant way.API-wise, shouldn’t
this.context.router.listen()
do this? I would expect that it abstracts away the history from me and knows about the component states since I get it from the context managed by a component.No, you need to track the actual rendered status of the
<Link>
itself.The way i’m solving this right now is to create a HOC around
<Link />
:I think its probably better to keep this behavior out of the core and document some patterns to solve this problem as not everyone wants this behavior.
Might be a hack, but
<Link ignoreChanges={animating}/>
could work, you’ll know you’re animating, so it doesn’t require extra finesse on the app’s part.It’s hard to imagine any other use-case than animation, and a quick prop hack will work w/o requiring a bunch of changes for this one thing.