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

New feature flags to help detect unexpected lifecycle side effects #11587

Merged
merged 4 commits into from
Nov 17, 2017

Conversation

bvaughn
Copy link
Contributor

@bvaughn bvaughn commented Nov 17, 2017

Avoiding side effects in the will-mount/will-update/etc lifecycle hooks becomes very important with async rendering. Unfortunately it's not always easy to detect. This PR adds 2 new feature flags (both disabled by default) to help with this. These flags invoke methods that are supposed to be side-effect-free a second time, roughly approximating what happens when React throws away incomplete work.

Before I started this, I planned to repeat the whole begin phase (eg: cWRP -> sCU -> cWU -> cWRP -> sCU -> cWU -> render) rather than just individual methods (eg cWRP -> cWRP -> sCU -> sCU -> cWU -> cWU -> render). That looks to be more complicated than I had assumed though, and I'm not convinced it's worth the extra effort and complexity. (Since these methods should not have side effects, it should be okay to call them in either sequence.) Happy to discuss this more in depth if others disagree though!

Once these flags are approved, my next step will be to connect them to a GK for the Facebook internal builds, similar to enableAsyncSchedulingByDefaultInReactDOM.

@@ -168,6 +171,11 @@ export default function(
);
stopPhaseTimer();

// Simulate an async bailout/interruption by invoking lifecycle twice.
if (invokePrecommitLifecycleHooksTwice) {
Copy link
Collaborator

@acdlite acdlite Nov 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the rationale for putting the second call after the timer has ended?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of these are after the timer. Didn't seem important to put before or after, so long as it was outside of the timer. If you prefer I change it, I'm happy to.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nah it's fine either way I think, just curious

@bvaughn
Copy link
Contributor Author

bvaughn commented Nov 17, 2017

I think I'll also double-invoke render. Will add that momentarily.

// Helps identify side effects in begin-phase lifecycle hooks:
export const invokePrecommitLifecycleHooksTwice = false;
// Helps identify side effects in setState callback:
export const invokeSetStateCallbackTwice = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a scenario where it's useful for these to be separate flags?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. Maybe it was mostly just a naming concern, which is kind of silly I guess. Happy to combine them. Any suggestion for a name that covers both?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

debugRenderPhaseSideEffects seems appropriately generic :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

genius

@acdlite
Copy link
Collaborator

acdlite commented Nov 17, 2017

Maybe we should put all these checks inside DEV blocks?

@bvaughn
Copy link
Contributor Author

bvaughn commented Nov 17, 2017

Maybe we should put all these checks behind DEV checks?

Considered this. Unfortunately doing that means that we (internally at Facebook) would be much less likely to see them while dog fooding.

@acdlite
Copy link
Collaborator

acdlite commented Nov 17, 2017

Hmm good point. Should get stripped out regardless.

@bvaughn bvaughn merged commit 7f68544 into facebook:master Nov 17, 2017
@bvaughn bvaughn deleted the doublemint-lifecycle-hooks branch November 17, 2017 18:49
Ethan-Arrowood pushed a commit to Ethan-Arrowood/react that referenced this pull request Dec 8, 2017
…acebook#11587)

Added `debugRenderPhaseSideEffects` feature flag to help detect unexpected side effects in pre-commit lifecycle hooks and `setState` reducers.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants