facebook/react

Recursive forceUpdate

tgriesser opened this issue ยท 15 comments

It would be nice if there were a way to call forceUpdate in a way that it would be applied recursively to children elements. I'm currently using shouldComponentUpdate paired with Immutable.js in a similar fashion to OM and I've found that this behavior can be preferable in some cases.

One concrete use case would be @gaearon's hot loader - which currently attempts to gather all of the elements and trigger a forceUpdate but it seems to still somehow be hitting shouldComponentUpdate in my application (haven't quite tracked down where/how).

Another use case would be as a simple solution to #2517 (the context / shouldComponentUpdate issue), when a context is changed you'd want to be able to forceUpdate on the element and all children.

Unfortunately this wouldn't help me because I still need to walk the tree to auto-bind hot-patched methods.

it seems to still somehow be hitting shouldComponentUpdate in my application (haven't quite tracked down where/how).

Should not be the case, I specifically checked for this. If you can put up a reproducible example, I can take a look.

I also use something akin to Om, my state is completely outside of React in a single js-based Atom.
Everything is always re-rendered from the very top in a pure functional way.

I want to be able to hot swap the user language, and to retranslate the React app in the target locale without having to refresh the whole html page.

I use React-intl which uses context.

I would be OK with a recursive forceUpdate of the top component on locale change.

Related:
formatjs/formatjs#58
#2517

Note that I have tested to unmount and remount the top-level node with the updated context.

What I can see is that if you unmount and remount the node in the same "event loop tick", visually it looks like a recursive forceUpdate: the component is not unmounted but simply rerendered from a fresh vdom (i guess).

It seems this behavior is constant when unmounting/remounting in same event loop, and can also appear (randomly) when a setTimeout 0 is introduced.

Never mind, I realized this can be accomplished quite easily by just setting the key to a unique value wherever you wish to remount the entire tree.

nice trick to know @tgriesser thanks

Quite useful, thanks @tgriesser

Never mind, I realized this can be accomplished quite easily by just setting the key to a unique value wherever you wish to remount the entire tree.

This would destroy the existing DOM though.

How about, when you change the context, walking all your children with React.Children.forEach and calling forceUpdate on them if they have their contextTypes set to your context element?

If that works I think it would be neat if React had a helper function that did this. Screen size changes, translations, global edit mode, โ€ฆ all kinds of seldom-changing things that benefit from being on context.

jimfb commented

@wmertens React.Children.forEach returns elements (not components) so you can't call forceUpdate. Regardless, the OP already linked the relevant issue (#2517).

FWIW I maintain https://github.com/gaearon/react-deep-force-update for my hot reloading purposes but it relies on React internals.

Ok, for now I'll just stick to the safe side and continue using redux for data that would be better stored in context. Sometimes that means I have 50 of store listeners on the page but luckily that doesn't seem to impact performance for my use cases.

Hi!

At first, I'm aware of @gaearon's react-deep-force-update but it seems it doesn't work on production build.

What I'm trying to solve is live retranslation of my page including re-executing router on feature/react-intl branch of react-starter-kit

What I'm worrying about is when I use @tgriesser's trick I can loose internal state of components (controlled or uncontrolled inputs...)
I don't try the trick but I'm expecting that it can be too ๐Ÿ› tricky for production..

Best if #2517 will be resolved and react-intl will be updated, but what I can do in meantime? May be I'm just doing something wrong...

We'll likely get back to this. There's another issue about forceDeepUpdate where it is tracked.