Top down rendering?
joelmoss opened this issue · 3 comments
So react-redux has a few performance optimisations built in, that I believe are important. The main one being that components are updated in a top down manner. So if parent and child components are subscribed to the same state, and that state changes, react-redux will make sure the parent component re-renders before the child.
How does react-recollect handle this?
This currently isn't handled explicitly. I will look into it.
I think it might already be optimal in most cases, but I'm lacking tests that explicitly assert this, so will at the very least add those before closing this.
Initial thoughts:
-
All updates happen via a simple
setState()
in the wrapper component, so updates are batched by React by default IF those updates originate from an event fired by a React component. E.g. React batches these two component updates. So I'm pretty sure "responding to user activity" updates are optimised.
-
Updates originating outside a React component (network responses etc) aren't batched by React, so are a candidate for optimisation (this would save CPU time, not reduce DOM updates). Perhaps in this case I can check
prevState
inshouldComponentUpdate
incollect.tsx
to see if a component has already been updated with the next store. (That second render only happens because the store is shallow cloned before setting state.)
-
Updates are fired in initial render order, and parent components start rendering before child components, so parent-first is the default. (I need to investigate if there's a case where a lower-level component could wind up before it's parent in the register of listeners).
-
I previously considered skipping component updates where an ancestor is flagged for an update too, but the possibility of an intermediate pure component means that a descendant/ancestor relationship between two components doesn't mean the lower-level one can be skipped. Of course, this doesn't mean rendering the parent first wouldn't be faster in the cases where it does trigger a re-render of the child.
-
First prize is letting React do the optimizations, so note to self: check out
unstable_batchedUpdates
exposed by ReactDOM.
Thanks for prompting me to dig into this @joelmoss.
Updating was optimal in most cases, but there were cases of wasted work, e.g.:
- a parent and child component are both wrapped in
collect
- the parent passes props to the child
- a store property used by both components is updated, triggering an update on both components
- the change is such that the props passed from parent to child are also updated (so now, both the parent component and Recollect want to re-render the child)
This was causing a double-render of the child, but is now fixed ( in 5.2.2
) using React's unstable_batchedUpdates
to ensure all updated components get a single render.
The scenario is covered with this test: https://github.com/davidgilbertson/react-recollect/blob/master/tests/integration/renderBatching.test.tsx
The React folks have kindly confirmed that unstable_batchedUpdates
isn't going to break outside of a semver change. facebook/react#18602.
Great stuff, thx 👌