Description
Previously: #11777 (comment)
Attempted (closed) resolution: #11819
The implementation of withSelect
attaches a store subscriber in its constructor
, assuming that the subscription would be removed in a subscription componentWillUnmount
. However, in the context of renderToString
, a constructor
is called but componentWillUnmount
will never be called. Thus, data-bound components will leave lingering subscription callbacks after being rendered via renderToString
.
From @jsnajdr at #11777 (comment)
Subscribing in constructor can cause subscriptions to leak in two cases:
- when server-side rendering, constructor is called, but
componentWillUnmount
never is.- in React Fiber concurrent mode, component instances can be constructed, but never actually committed to DOM. This can happen when Fiber is working through rendering a low-priority update (calling constructors and
render
methods) and suddenly a higher priority update is scheduled that invalidates the work that's been done. Then the unfinished low-priority work will be thrown away and restarted. In such a case, constructor is called, but thecomponent(DidMount|WillUnmount)
methods aren't.The correct place to subscribe is therefore always
componentDidMount
.Then, of course, we might miss a store update that happened between constructor and
componentDidMount
.
react-redux
solves that by rerunning the selector (i.e.,mapStateToProps
) incomponentDidMount
and callingforceUpdate
if anything changed. That's the stable v5.1.1.In master, they have an unreleased beta version where the Redux provider and consumer are rewritten using the new React context API and where the
connect
-ed consumers don't subscribe to the store at all. Just the Provider does. That could be an inspiration for the@wordpress/data
internals, too 🙂Conclusion: this patch solves the bug that @Tug discovered, but other subtle issues are still present.