This strategy finds the current fiber. It traverses back up to the root if
the two trees are completely separate and determines which one is current.
If the two trees converge anywhere along the way, we assume that is the
current tree. We find the current child by searching the converged child
set.
This could fail if there's any way for both return pointers to point
backwards to the work in progress. I don't think there is but I could be
wrong.
This may also fail on coroutines where we have reparenting situations.
Fixes a bug when updating from a single text child (or
dangerouslySetInnerHTML) to regular children, where the previous
text content never gets deleted.
* Exit early in scheduleUpdate if a node's priority matches
This is a performance optimization and is unobservable. However, it
helps protect against regressions on the following invariants on which
it relies:
- The priority of a fiber is greater than or equal to the priority of
all its descendent fibers.
- If a tree has pending work priority, its root is scheduled.
* New error boundary semantics
- Recovering from an error boundary no longer uses Task priority by
default. The work is scheduled using whatever priority created the
error.
- Error handling is now a side-effect that happens during the
commit phase.
- The default behavior of an error boundary is to render null. Errors
do not propagate except when an boundary fails. Conceptually, this would
be like throwing an error from a catch block.
- A host container is treated like a no-op error boundary. The first
error captured by a host container is thrown at the end of the batch.
Like with normal error boundaries, the entire tree is unmounted.
* Fix broken setState callback test
* Add test for "unwinding" context when an error interrupts rendering
* Switch over primary effect types only
This avoids the need to create an export for every combination of bits.
* Only continue the work loop if the error was successfully captured
* Add more tests for incremental error handling
These tests are currently failing:
✕ catches render error in a boundary during partial deferred mounting
✕ catches render error in a boundary during animation mounting
✕ propagates an error from a noop error boundary during full deferred mounting
✕ propagates an error from a noop error boundary during partial deferred mounting
✕ propagates an error from a noop error boundary during animation mounting
The observed behavior is that unstable_handleError() unexpected gets called twice:
"ErrorBoundary render success",
"BrokenRender",
"ErrorBoundary unstable_handleError",
+ "ErrorBoundary render success",
+ "BrokenRender",
+ "ErrorBoundary unstable_handleError",
"ErrorBoundary render error"
* Verify batched updates get scheduled despite errors
* Add try/catch/finally blocks around commit phase passes
We'll consolidate all these blocks in a future PR that refactors the
commit phase to be separate from the perform work loop.
* NoopBoundary -> RethrowBoundary
* Only throw uncaught error once there is no more work to perform
* Remove outdated comment
It was fixed in #8451.
* Record tests
* Always reset nextUnitOfWork on error
This is important so that the test at the end of performAndHandleErrors() knows it's safe to rethrow.
* Add a passing test for unmounting behavior on crashed tree
* Top-level errors
An error thrown from a host container should be "captured" by the host
container itself
* Remove outdated comment
* Separate Rethrow and Noop scenarios in boundary tests
* Move try block outside the commit loops
* Make bad element type message same as in Stack
This makes Fiber emit the same message as Stack (aside from the missing owner information).
* Add a separate test verifying error includes owner name
Fiber currently doesn't pass it. This is just to keep track of it as a todo.
* Add iterable cases to MultiChildReconcile test
Stack currently supports rendering iterables, but Fiber does not.
Previously we didn't have any public API tests for iterables. We have tests for traverseAllChildren() which is shared between React.Children and Stack. However Fiber doesn't currently use it, and likely won't. So this commit is a first step towards actually testing iterable support via public API. The next step will be to port traverseAllChildren() tests to test React.Children API instead.
* Implement iterable reconciliation in Fiber
This uses the same exact algorithm as array reconciliation but uses iterator to step through.
This gets reconcile tests to pass again but introduces a regression in ReactMultiChildText case which uses Maps as children. It passed before because Maps were ignored, but now it's failing because this actually runs the Map code path in Fiber. We can throw early in this case when we want to follow up on this.
* Rewrite traverseAllChildren() tests against React.Children API
This function was used in React.Children and Stack.
The corresponding reconciliation functionality is being tested by ReactMultiChild tests.
So we can move these tests to ReactChildren and test its public API.
* Use a closure to bind gaurded callback
This way the fake event isn't being implicitly passed into the event handler
* Add tests for ReactErrorUtils
Add fiber test report
Linting fixes
We used to terminate the search on host nodes, and then use the nested unmount algorithm.
However this means we didn't unmount portals inside the host nodes.
We will probably need to restructure this somehow but for now I just added a recursive call to unblock myself.
* Remove output field
The idea was originally that each fiber has a return value. In practice
most of what we're modelling here are void functions and we track side
effects instead of return values.
We do use this for coroutines to short cut access to terminal yields.
However, since this can be nested fragments we end up searching the tree
anyway. We also have to manage this in transferOutput so it ends up being
as expensive. Maybe we can save some traversal for updates when coroutine
branches bail out but meh.
* Unmount child from the first phase of a coroutine
This removes updateContainer and instead uses the regular child mutation
methods to insert into the root container and portals.
Since we're no longer clearing out the container DOM in updateContainer
we have to do that manually during initial mount. This now works on a
document and one of the tests end up unmounting the body when you render
into the document so I had to work around that bit since we don't yet
properly support rendering into the document root.
I tried to add a temporary check for the correct state in https://gist.github.com/spicyj/338147e989215b6eeaf48a6ce2d68d93 and run our test suites over it, but none of our existing test cases would have triggered that invariant. The new one I added does.
We're walking backwards up to the root to find the parent so that we can
propagate events further up to nested React parents. If we don't find a
root, that means that the tree was unmounted and we shouldn't send any
events to it.