Commit Graph

3074 Commits

Author SHA1 Message Date
Sebastian Markbåge a511dc7090 Error for deferred value and transition in Server Components (#20657) 2021-01-25 13:58:47 -08:00
Sebastian Markbåge fb3f63f1ab Remove lazy invokation of segments (#20656)
This is a remainder from Blocks when these were separate query functions.
2021-01-25 13:04:36 -08:00
Brian Vaughn 6d94017c42 DevTools: Make it easier to write tests for inspected elements (#20655)
And also add a few tests for  which also cover a recent bugfix that just landed
2021-01-25 14:58:19 -05:00
Berton Zhu f0031dc6ed Devtool: $r should contain hooks property when it is forwardRef or memo component (#20626) 2021-01-25 10:35:02 -05:00
Brian Vaughn 895ae67fd3 Improve error boundary handling for unmounted subtrees (#20645)
A passive effect's cleanup function may throw after an unmount. Prior to this commit, such an error would be ignored. (React would not notify any error boundaries.)

After this commit, React will skip any unmounted boundaries and look for a still-mounted boundary. If one is found, it will call getDerivedStateFromError and/or componentDidCatch (depending on the type of boundary). Unmounted boundaries will be ignored, but as they have been unmounted– this seems appropriate.
2021-01-25 08:54:20 -05:00
Andrew Clark f15f8f64bb Store interleaved updates on separate queue until end of render (#20615)
## Motivation

An *interleaved* update is one that is scheduled while a render is
already in progress, typically from a concurrent user input event.

We have to take care not to process these updates during the current
render, because a multiple interleaved updates may have been scheduled
across many components; to avoid tearing, we cannot render some of
those updates without rendering all of them.

## Old approach

What we currently do when we detect an interleaved update is assign a
lane that is not part of the current render.

This has some unfortunate drawbacks. For example, we will eventually run
out of lanes at a given priority level. When this happens, our last
resort is to interrupt the current render and start over from scratch.
If this happens enough, it can lead to starvation.

More concerning, there are a suprising number of places that must
separately account for this case, often in subtle ways. The maintenance
complexity has led to a number of tearing bugs.

## New approach

I added a new field to the update queue, `interleaved`. It's a linked
list, just like the `pending` field. When an interleaved update is
scheduled, we add it to the `interleaved` list instead of `pending`.

Then we push the entire queue object onto a global array. When the
current render exits, we iterate through the array of interleaved queues
and transfer the `interleaved` list to the `pending` list.

So, until the current render has exited (whether due to a commit or an
interruption), it's impossible to process an interleaved update, because
they have not yet been enqueued.

In this new approach, we don't need to resort to clever lanes tricks to
avoid inconsistencies. This should allow us to simplify a lot of the
logic that's currently in ReactFiberWorkLoop and ReactFiberLane,
especially `findUpdateLane` and `getNextLanes`. All the logic for
interleaved updates is isolated to one place.
2021-01-22 14:01:54 -08:00
Andrew Clark 0fd6805c6d Land rest of effects refactor in main fork (#20644) 2021-01-22 14:49:33 -05:00
Brian Vaughn a6b5256a29 Refactored recursive strict effects method to be iterative (#20642) 2021-01-22 11:27:39 -08:00
Brian Vaughn 3957853ae5 Re-add "strict effects mode" for legacy roots only (#20639)
This combines changes originally made in #19523, #20028, and #20415 but with slightly different semantics: "strict effects" mode is enabled only for the experimental root APIs (never for legacy render, regardless of <StrictMode> usage). These semantics may change slightly in the future.
2021-01-22 08:58:11 -05:00
Andrew Clark fceb75e899 Delete remaining references to effect list (#20625)
I think that's it!
2021-01-20 10:24:01 -08:00
Andrew Clark 741dcbdbec Schedule passive phase whenever there's a deletion (#20624)
We use the passive phase to detach the fibers.
2021-01-20 10:21:42 -08:00
Andrew Clark 11a983fc76 Remove references to Deletion flag (#20623)
We no longer use the Deletion flag anywhere in the new fork, so we can
stop marking it.
2021-01-20 10:18:19 -08:00
Dima Tisnek 2e948e0d91 Avoid .valueOf to close #20594 (#20617) 2021-01-19 20:59:31 -05:00
Andrew Clark 2a646f73e4 Convert snapshot phase to depth-first traversal (#20622) 2021-01-19 15:37:00 -08:00
Andrew Clark fb3e158a64 Convert ReactSuspenseWithNoopRenderer tests to use built-in cache (#20601)
* Remove `ms` prop from SuspenseWithNoop tests

Use `resolveText` instead.

* Migrate SuspenseWithNoop tests to built-in cache
2021-01-19 14:38:54 -08:00
Ricky e0fd9e67fc Use update lane priority in work loop (#20621) 2021-01-19 17:34:08 -05:00
Andrew Clark 58e8304483 Remove custom error message from hook access error (#20604)
It will still result in a null access error, so there's no change in
semantics. We will print a user-friendly error message in DEV.
2021-01-19 14:20:22 -08:00
Andrew Clark 9043626f09 Cache tests: Make it easier to test many caches (#20600)
Some rearranging to make it easier to write tests that assert on the
output of multiple caches.
2021-01-19 13:54:45 -08:00
Andrew Clark af0bb68e87 Land #20595 and #20596 in main fork (#20602) 2021-01-19 08:37:51 -08:00
ChenLei ba9582da27 [devtools] Fix can't expand prop value in some scenario (#20534)
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
2021-01-19 10:26:52 -05:00
Brian Vaughn af16f755dc Update DevTools to use getCacheForType API (#20548)
DevTools was built with a fork of an early idea for how Suspense cache might work. This idea is incompatible with newer APIs like `useTransition` which unfortunately prevented me from making certain UX improvements. This PR swaps out the primary usage of this cache (there are a few) in favor of the newer `unstable_getCacheForType` and `unstable_useCacheRefresh` APIs. We can go back and update the others in follow up PRs.

### Messaging changes

I've refactored the way the frontend loads component props/state/etc to hopefully make it better match the Suspense+cache model. Doing this gave up some of the small optimizations I'd added but hopefully the actual performance impact of that is minor and the overall ergonomic improvements of working with the cache API make this worth it.

The backend no longer remembers inspected paths. Instead, the frontend sends them every time and the backend sends a response with those paths. I've also added a new "force" parameter that the frontend can use to tell the backend to send a response even if the component hasn't rendered since the last time it asked. (This is used to get data for newly inspected paths.)

_Initial inspection..._
```
front |                                                      | back
      | -- "inspect" (id:1, paths:[], force:true) ---------> |
      | <------------------------ "inspected" (full-data) -- |
```
_1 second passes with no updates..._
```
      | -- "inspect" (id:1, paths:[], force:false) --------> |
      | <------------------------ "inspected" (no-change) -- |
```
_User clicks to expand a path, aka hydrate..._
```
      | -- "inspect" (id:1, paths:['foo'], force:true) ----> |
      | <------------------------ "inspected" (full-data) -- |
```
_1 second passes during which there is an update..._
```
      | -- "inspect" (id:1, paths:['foo'], force:false) ---> |
      | <----------------- "inspectedElement" (full-data) -- |
```

### Clear errors/warnings transition
Previously this meant there would be a delay after clicking the "clear" button. The UX after this change is much improved.

### Hydrating paths transition
I also added a transition to hydration (expanding "dehyrated" paths).

### Better error boundaries
I also added a lower-level error boundary in case the new suspense operation ever failed. It provides a better "retry" mechanism (select a new element) so DevTools doesn't become entirely useful. Here I'm intentionally causing an error every time I select an element.

### Improved snapshot tests
I also migrated several of the existing snapshot tests to use inline snapshots and added a new serializer for dehydrated props. Inline snapshots are easier to verify and maintain and the new serializer means dehydrated props will be formatted in a way that makes sense rather than being empty (in external snapshots) or super verbose (default inline snapshot format).
2021-01-19 09:51:32 -05:00
Andrew Clark 95feb0e701 Convert mutation phase to depth-first traversal (#20596) 2021-01-15 12:24:20 -08:00
Andrew Clark 6132919bf2 Convert layout phase to depth-first traversal (#20595) 2021-01-15 12:22:23 -08:00
Andrew Clark 42e04b46d1 Fix: Detach deleted fiber's alternate, too (#20587)
We need to call `detachFiberAfterEffects` on the fiber's alternate to
clean it up. We're currently not, because the `alternate` field is
cleared during `detachFiberMutation`. So I deferred detaching the
`alternate` until the passive phase. Only the `return` pointer needs to
be detached for semantic purposes.

I don't think there's any good way to test this without using
reflection. It's not even observable using out our "supported"
reflection APIs (`findDOMNode`), or at least not that I can think of.
Which is a good thing, in a way.

It's not really a memory leak, either, because the only reference to the
alternate fiber is from the parent's alternate. Which will be
disconnected the next time the parent is updated or deleted.

It's really only observable if you mess around with internals in ways
you're not supposed to — I found it because a product test in www that
uses Enzyme was doing just that.

In lieu of a new unit test, I confirmed this patch fixes the broken
product test.
2021-01-14 08:18:55 -08:00
Andrew Clark a656ace8da Deletion effects should fire parent -> child (#20584)
* Test: Deletion effects should fire parent -> child

Regression in new effect implementation

* Fix passive deletion effect ordering
2021-01-13 16:18:55 -08:00
Christian Ruigrok e8eff119e0 Fix ESLint crash on empty react effect hook (#20385)
* Fix ESLint crash on empty react effect hook

* Add layout effect to test

* Improve wording in comment

* Improve lint warning wording

* Reword missing effect callback message
2021-01-11 15:18:45 -05:00
Brian Vaughn 27659559eb Add useRefresh hook to react-debug-tools (#20460) 2021-01-04 10:46:20 -05:00
Jaiwanth beb38aba3e [devtools] Bump electron version from 9.1.0 to 11.1.0 for darwin-arm64 builds (#20496) 2021-01-04 10:38:11 -05:00
Brian Vaughn 6630c2de2a Add rudimentary support for Cache to DevTools (#20458) 2021-01-04 09:32:03 -05:00
Brian Vaughn 50393dc3a0 React Native fixes for new inline errors feature (#20502) 2020-12-22 13:58:47 -05:00
Sebastian Silbermann 09a2c363a5 Expose DEV-mode warnings in devtools UI (#20463)
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
2020-12-22 11:09:29 -05:00
Sebastian Silbermann 6cbb9394d1 devtools: Display shortcuts for prev/next search result (#20470) 2020-12-20 21:48:36 -05:00
Andrew Clark 99554dc36f Add Flight packages to experimental allowlist (#20486)
- react-fetch
- react-fs
- react-pg
- react-server-dom-webpack
2020-12-18 14:29:48 -08:00
Andrew Clark efc57e5cbb Add built-in Suspense cache with support for invalidation (refreshing) (#20456) 2020-12-18 10:57:24 -08:00
Andrew Clark 00a5b08e24 Remove PassiveStatic optimization
Passive flags are a new concept that is tricky to get right. We've
already found two bugs related to PassiveStatic. Let's remove this
optimization for now, and add it back once the main part of the effects
refactor lands.
2020-12-18 11:31:35 -06:00
Andrew Clark a6329b1050 Don't clear static flags in resetWorkInProgress
Fixes the regression test added in #20433
2020-12-18 11:30:20 -06:00
Andrew Clark 1cf59f34b8 Convert passive unmount phase to tree traversal 2020-12-18 11:29:38 -06:00
Andrew Clark ab29695a05 Defer more field detachments to passive phase
This allows us to use those fields during passive unmount traversal.
2020-12-18 11:28:49 -06:00
Andrew Clark d37d7a4bb4 Convert passive mount phase to tree traversal 2020-12-18 11:27:53 -06:00
Andrew Clark 19e15a3986 Add PassiveStatic to trees with passive effects
Indicates that a tree needs passive clean-up on deletion.
2020-12-18 11:27:08 -06:00
Andrew Clark ff17fc176f Don't clear other flags when adding Deletion
Same as #20398 but for Deletions. There's no new regression test, but in
the effects refactor, existing tests will fail without this.
2020-12-17 16:31:50 -06:00
Ricky 5687864eb7 Add back disableSchedulerTimeoutInWorkLoop flag (#20482)
* Add back enableSchedulerTimeoutInWorkLoop flag

* Nvm, keep it as disableSchedulerTimeoutInWorkLoop
2020-12-17 17:17:23 -05:00
Luna Ruan 9f338e5d77 clone json obj in react native flight client host config parser (#20474)
As per Seb's comment in #20465, we need to do the same thing in React Native as we do in Relay.

When `parseModel` suspends because of missing dependencies, it will exit and retry to parse later. However, in the relay implementation, the model is an object that we modify in place when we parse it, so when we we retry, part of the model might be parsed already into React elements, which will error because the parsing code expect a Flight model. This diff clones instead of mutating the original model, which fixes this error.
2020-12-16 11:53:51 -08:00
Luna Ruan 4e62fd2712 clone json obj in relay flight client host config parser (#20465)
When `parseModel` suspends because of missing dependencies, it will exit and retry to parse later. However, in the relay implementation, the model is an object that we modify in place when we parse it, so when we we retry, part of the model might be parsed already into React elements, which will error because the parsing code expect a Flight model. This diff clones instead of mutating the original model, which fixes this error.
2020-12-15 15:33:54 -08:00
Oliver Lassen 604bbcd87d [devtools] Increase the clickable area of the prop value (#20428) 2020-12-14 16:23:26 -05:00
Dan Abramov 070372cde2 [Flight] Fix webpack watch mode issue (#20457) 2020-12-14 15:50:20 +00:00
Dan Abramov 0f80dd1484 [Flight] Support concatenated modules in Webpack plugin (#20449)
* Extract recordModule

* Add support for concatenated modules
2020-12-13 17:44:59 +00:00
Dan Abramov daf38ecdfc [Flight] Use lazy reference for existing modules (#20445) 2020-12-11 22:45:18 +00:00
Andrew Clark 3f9205c333 Regression test: SuspenseList causes lost unmount (#20433)
@sebmarkbage reminded me that the complete phase of SuspenseList
will sometimes enter the begin phase of the children without calling
`createWorkInProgress` again, instead calling `resetWorkInProgress`.

This was raised in the context of considering whether #20398 might
have accidentally caused a SuspenseList bug. (I did look at this code
at the time, but considering how complicated SuspenseList is it's not
hard to imagine that I made a mistake.)

Anyway, I think that PR is fine; however, reviewing it again did lead me
to find a different bug. This new bug is actually a variant of the bug
fixed by #20398.

`resetWorkInProgress` clears a fiber's static flags. That's wrong, since
static flags -- like PassiveStatic -- are meant to last the lifetime of
the component.

In more practical terms, what happens is that if a direct child of
SuspenseList contains a `useEffect`, then SuspenseList will cause the
child to "forget" that it contains passive effects. When the child
is deleted, its unmount effects are not fired :O

This is the second of this type of bug I've found, which indicates to me
that it's too easy to accidentally clear static flags.

Maybe we should only update the `flags` field using helper functions,
like we do with `lanes`.

Or perhaps we add an internal warning somewhere that detects when a
fiber has different static flags than its alternate.
2020-12-11 08:38:49 -08:00
Sebastian Markbåge cdfde3ae11 Always rethrow original error when we replay errors (#20425)
We replay errors so you can break on paused exceptions. This is done in
the second pass so that the first pass can ignore suspense.

Originally this threw the original error. For suppression purposes
we copied the flag onto the original error.

https://github.com/facebook/react/blob/f1dc626b29b8bf0f14c75a8525e8650b7ea94a47/packages/react-reconciler/src/ReactFiberScheduler.old.js#L367-L369

During this refactor it changed to just throw the retried error:

https://github.com/facebook/react/pull/15151

We're not sure exactly why but it was likely just an optimization or
clean up.

So we can go back to throwing the original error. That helps in the case
where a memoized function is naively not rethrowing each time such as
in Node's module system.

Unfortunately this doesn't fix the problem fully.
Because invokeGuardedCallback captures the error and logs it to the browser.
So you still end up seeing the wrong message in the logs.

This just fixes so that the error boundary sees the first one.
2020-12-10 05:50:41 -08:00