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

[Fiber] Initial error boundaries #7993

Closed
wants to merge 2 commits into from
Closed

[Fiber] Initial error boundaries #7993

wants to merge 2 commits into from

Conversation

gaearon
Copy link
Collaborator

@gaearon gaearon commented Oct 17, 2016

This builds on top of #7941 + new tests I added in #7949 (hence the master merge commit).
It adds basic support for error boundaries during mount to Fiber.

Commit for review: 833a7f8.

Test plan: npm test -- ErrorB.

 › Ran all tests matching "ErrorB".
 › 13 tests failed, 14 tests passed (27 total in 1 test suite, run time 1.545s)

Most of those 13 failing tests are failing because of the lack of componentWillUpdate and componentWillReceiveProps.

A few thoughts:

  • This my first "real" Fiber PR so I have no idea what I'm doing.
  • Adding a flag to all fibers seems bad. I'm not sure where to keep that state though. I need to store somewhere that we're "retrying" and if we fail, we should propagate error up. We used to rely on stack for this.
  • I added some code to handle setState in componentWillMount.
  • The part where I put the error flag and try to clear all work in progress is funny. Is there a better way?
  • Neat: errors in setState() are now caught and I didn't have to do anything special to make that works 😄 .

@sebmarkbage
Copy link
Collaborator

I think the best strategy would be to do the try catch right outside the while loop so that we don't go in and out of try statements.

https://github.com/facebook/react/blob/master/src/renderers/shared/fiber/ReactFiberScheduler.js#L230

You'll know which one failed because it is the current value of "nextUnitOfWork".

@acdlite
Copy link
Collaborator

acdlite commented Oct 17, 2016

Can you rebase instead of merging from master to prevent the duplicate commits?

@gaearon
Copy link
Collaborator Author

gaearon commented Oct 17, 2016

I didn't want to rebase Seb's commits (they're still not in master).
I needed master though because of my own commits there.

@acdlite
Copy link
Collaborator

acdlite commented Oct 17, 2016

They are in master now

@gaearon
Copy link
Collaborator Author

gaearon commented Oct 17, 2016

Rebased.

// This flag gets set to true for error boundaries when they attempt to
// render the error path. This way we know that if rendering fails, we should
// skip this error boundary as failed and propagate the error above.
hasErrored: boolean,
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess, the question is, what priority should the error have?

A) If no other priority can beat it, then we should just do this in a synchronous loop in place of performDeferredWork. If that's the case, then you can just have a separate try/catch around that one.

B) If another priority can render higher than the error set state, then this flag can be invalidated before we get around to rendering the error. Since we can still update the state of the tree before it errored.

So, I think A is probably the easiest option.

handleErrorInBoundary(errorBoundary, error);
return;
}
// TODO: Do we need to reset nextUnitOfWork here?
Copy link
Collaborator

Choose a reason for hiding this comment

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

It is always safe to set nextUnitOfWork to null because it will just find its place again.


function handleErrorInBoundary(errorBoundary : Fiber, error : any) {
// The work below failed so we need to clear it out and try to render the error state.
// TODO: Do we need to clear all of these fields? How do we teardown an existing tree?
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we naively just clear everything here, we'll lose the ability to unmount them. I don't think we need to clear anything here.

We normally we reset everything to whatever the "current" tree represents on the way down the tree. The simplest way might be to restart from the root.

In theory the error boundary will already be a clone, it might be fine to just restart from it. However, unstable_handleError may be calling setState on a component above (or even a sibling) and that will start screwing everything up. If you restart from the root, that case will be covered.

@gaearon
Copy link
Collaborator Author

gaearon commented Oct 24, 2016

Closing because I accidentally nuked my fork (and needs rebasing anyway).

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.

4 participants