Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Data: withSelect: Subscription callbacks linger after renderToString #13879

Closed
aduth opened this issue Feb 14, 2019 · 3 comments
Closed

Data: withSelect: Subscription callbacks linger after renderToString #13879

aduth opened this issue Feb 14, 2019 · 3 comments
Labels
[Package] Data /packages/data [Type] Bug An existing feature does not function as intended

Comments

@aduth
Copy link
Member

aduth commented Feb 14, 2019

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 the component(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) in componentDidMount and calling forceUpdate 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.

@aduth aduth added [Type] Bug An existing feature does not function as intended [Package] Data /packages/data labels Feb 14, 2019
@aduth
Copy link
Member Author

aduth commented Mar 5, 2019

It was brought to my attention that this can cause some issues / strange behaviors with our use of React.StrictMode, where StrictMode will intentionally trigger multiple calls to functions which are meant to have no side effects (including constructor).

See: https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects

@jsnajdr
Copy link
Member

jsnajdr commented Mar 8, 2019

StrictMode will intentionally trigger multiple calls to functions which are meant to have no side effects

😄 that's somewhat evil 😄

@aduth
Copy link
Member Author

aduth commented Jun 10, 2019

I've confirmed that this was fixed by #15737 . In the process of confirming, however, another unrelated issue was surfaced, currently proposed for fix at #15873 .

@aduth aduth closed this as completed Jun 10, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Data /packages/data [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

No branches or pull requests

2 participants