Commit Graph

698 Commits

Author SHA1 Message Date
Andrew Clark 58742c21b8 Delete unused eventTimes Fiber field (#26599) 2023-04-11 08:23:04 -04:00
Jan Kassens da94e8b24a Revert "Cleanup enableSyncDefaultUpdate flag (#26236)" (#26528)
This reverts commit b2ae9ddb3b.

While the feature flag is fully rolled out, these tests are also testing
behavior set with an unstable flag on root, which for now we want to
preserve.

Not sure if there's a better way then adding a dynamic feature flag to
the www build?
2023-04-04 10:08:14 -04:00
Andrew Clark 09c8d25633 Move update scheduling to microtask (#26512)
When React receives new input (via `setState`, a Suspense promise
resolution, and so on), it needs to ensure there's a rendering task
associated with the update. Most of this happens
`ensureRootIsScheduled`.

If a single event contains multiple updates, we end up running the
scheduling code once per update. But this is wasteful because we really
only need to run it once, at the end of the event (or in the case of
flushSync, at the end of the scope function's execution).

So this PR moves the scheduling logic to happen in a microtask instead.
In some cases, we will force it run earlier than that, like for
`flushSync`, but since updates are batched by default, it will almost
always happen in the microtask. Even for discrete updates.

In production, this should have no observable behavior difference. In a
testing environment that uses `act`, this should also not have a
behavior difference because React will push these tasks to an internal
`act` queue.

However, tests that do not use `act` and do not simulate an actual
production environment (like an e2e test) may be affected. For example,
before this change, if a test were to call `setState` outside of `act`
and then immediately call `jest.runAllTimers()`, the update would be
synchronously applied. After this change, that will no longer work
because the rendering task (a timer, in this case) isn't scheduled until
after the microtask queue has run.

I don't expect this to be an issue in practice because most people do
not write their tests this way. They either use `act`, or they write
e2e-style tests.

The biggest exception has been... our own internal test suite. Until
recently, many of our tests were written in a way that accidentally
relied on the updates being scheduled synchronously. Over the past few
weeks, @tyao1 and I have gradually converted the test suite to use a new
set of testing helpers that are resilient to this implementation detail.

(There are also some old Relay tests that were written in the style of
React's internal test suite. Those will need to be fixed, too.)

The larger motivation behind this change, aside from a minor performance
improvement, is we intend to use this new microtask to perform
additional logic that doesn't yet exist. Like inferring the priority of
a custom event.
2023-03-31 13:04:08 -04:00
Andrew Clark 2d51251e60 Clean up deferRenderPhaseUpdateToNextBatch (#26511)
This is a change to some undefined behavior that we though we would do
at one point but decided not to roll out. It's already disabled
everywhere, so this just deletes the branch from the implementation and
the tests.
2023-03-30 14:10:19 -04:00
Jan Kassens afea1d0c53 [flow] make Flow suppressions explicit on the error (#26487)
Added an explicit type to all $FlowFixMe suppressions to reduce
over-suppressions of new errors that might be caused on the same lines.

Also removes suppressions that aren't used (e.g. in a `@noflow` file as
they're purely misleading)

Test Plan:
yarn flow-ci
2023-03-27 13:43:04 +02:00
Sebastian Silbermann d12bdcda69 Fix Flow types of useEffectEvent (#26468)
## Summary

Just copied the types over from the internal types. Type error was
hidden by overly broad FlowFixMe. With `$FlowFixMe[not-a-function]` we
would've seen the actual issue:
```
Cannot return `dispatcher.useEffectEvent(...)` because  `T` [1] is incompatible with  undefined [2].Flow(incompatible-return)
```

## How did you test this change?

- [x] yarn flow dom-node
- [x] CI
2023-03-25 20:24:00 +01:00
Leedom c0b34bc5fb chore: update links of docs and api (#26455)
Update new links of docs and api  for react package.
> [Documentation](https://react.dev/)
> [API](https://react.dev/reference/react)
2023-03-22 12:56:18 +01:00
Ibrahim Amin 163d86e195 Updated comment message (#26158)
a simple grammar fix.
2023-03-17 14:48:44 +00:00
Sebastian Markbåge d310d654a7 Avoid meta programming to initialize functions in module scope (#26388)
I'm trying to get rid of all meta programming in the module scope so
that closure can do a better job figuring out cyclic dependencies and
ability to reorder.

This is converting a lot of the patterns that assign functions
conditionally to using function declarations instead.

```
let fn;
if (__DEV__) {
  fn = function() {
    ...
  };
}
```
->
```
function fn() {
  if (__DEV__) {
    ...
  }
}
```
2023-03-14 21:00:22 -04:00
Andrew Clark 6334614860 Add disableLegacyContext test gates where needed (#26371)
The www builds include disableLegacyContext as a dynamic flag, so we
should be running the tests in that mode, too. Previously we were
overriding the flag during the test run. This strategy usually doesn't
work because the flags get compiled out in the final build, but we
happen to not test www in build mode, only source.

To get of this hacky override, I added a test gate to every test that
uses legacy context. When we eventually remove legacy context from the
codebase, this should make it slightly easier to find which tests are
affected. And removes one more hack from our hack-ridden test config.

Given that sometimes www has features enabled that aren't on in other
builds, we might want to consider testing its build artifacts in CI,
rather than just source. That would have forced this cleanup to happen
sooner. Currently we only test the public builds in CI.
2023-03-11 15:32:02 -05:00
Andrew Clark a8875eab7f Update more tests to not rely on sync queuing (#26358)
This fixes a handful of tests that were accidentally relying on React
synchronously queuing work in the Scheduler after a setState.

Usually this is because they use a lower level SchedulerMock method
instead of either `act` or one of the `waitFor` helpers. In some cases,
the solution is to switch to those APIs. In other cases, if we're
intentionally testing some lower level behavior, we might have to be a
bit more clever.

Co-authored-by: Tianyu Yao <skyyao@fb.com>
2023-03-10 11:06:28 -05:00
Andrew Clark 62cd5af08e Codemod redundant async act scopes (#26350)
Prior to #26347, our internal `act` API (not the public API) behaved
differently depending on whether the scope function returned a promise
(i.e. was an async function), for historical reasons that no longer
apply. Now that this is fixed, I've codemodded all async act scopes that
don't contain an await to be sync.

No pressing motivation other than it looks nicer and the codemod was
easy. Might help avoid confusion for new contributors who see async act
scopes with nothing async inside and infer it must be like that for a
reason.
2023-03-08 16:40:23 -05:00
Sebastian Markbåge d8e49f2af8 Use setTimeout to schedule work on the server in Edge environments (#26348)
We rely heavily on being able to batch rendering after multiple fetches
etc. have completed on the server. However, we only do this in the
Node.js build. Node.js `setImmediate` has the exact semantics we need.
To be after the current cycle of I/O so that we can collect after all
those I/O events already in the queue has been processed.

This doesn't exist in standard browsers, so we ended up not using it
there. We could've used `setTimeout` but that risks being throttled
which would severely negatively affect the performance so we just did it
synchronously there. We probably could just use the `scheduler` there.

Now we have a separate build for Edge where `setTimeout(..., 0)`
actually behaves like `setImmediate` which is what we want. So we can
just use that in that build.

@Jarred-Sumner not sure what you want for Bun.
2023-03-08 15:34:29 -05:00
Andrew Clark 44d3807945 Move internalAct to internal-test-utils package (#26344)
This is not a public API. We only use it for our internal tests, the
ones in this repo. Let's move it to this private package. Practically
speaking this will also let us use async/await in the implementation.
2023-03-08 12:58:31 -05:00
Andrew Clark 702fc984e6 Codemod act -> await act (4/?) (#26338)
Similar to the rationale for `waitFor` (see #26285), we should always
await the result of an `act` call so that microtasks have a chance to
fire.

This only affects the internal `act` that we use in our repo, for now.
In the public `act` API, we don't yet require this; however, we
effectively will for any update that triggers suspense once `use` lands.
So we likely will start warning in an upcoming minor.
2023-03-08 11:36:05 -05:00
Andrew Clark 703c67560d Codemod act -> await act (1/?) (#26334)
Similar to the rationale for `waitFor` (see
https://github.com/facebook/react/pull/26285), we should always await
the result of an `act` call so that microtasks have a chance to fire.

This only affects the internal `act` that we use in our repo, for now.
In the public `act` API, we don't yet require this; however, we
effectively will for any update that triggers suspense once `use` lands.
So we likely will start warning in an upcoming minor.
2023-03-07 10:15:34 -05:00
Andrew Clark b380c24852 Convert class equivlance tests to flushSync (#26333)
There's an old collection of test suites that test class component
behavior across ES6 (regular JavaScript classes), CoffeeScript classes,
and TypeScript classes. They work by running the same tests in all
environments and comparing the results.

Rather than use `act` or `waitFor` in these, I've changed them to use
`flushSync` instead so that they can flush synchronously. The reason is
that CoffeeScript doesn't have async/await, so we'd have to write those
tests differently than how they are written in the corresponding
modules. Since none of these tests cover any concurrent behavior, I
believe it's fine in this case to do everything synchronously; they
don't use any concurrent features, anyway, so effectively it's just
skipping a microtask.
2023-03-07 10:14:41 -05:00
Andrew Clark 1528c5ccdf SchedulerMock.unstable_yieldValue -> SchedulerMock.log (#26312)
(This only affects our own internal repo; it's not a public API.)

I think most of us agree this is a less confusing name. It's possible
someone will confuse it with `console.log`. If that becomes a problem we
can warn in dev or something.
2023-03-06 11:09:07 -05:00
Andrew Clark 25685d8a90 Codemod tests to waitFor pattern (9/?) (#26309)
This converts some of our test suite to use the `waitFor` test pattern,
instead of the `expect(Scheduler).toFlushAndYield` pattern. Most of
these changes are automated with jscodeshift, with some slight manual
cleanup in certain cases.

See #26285 for full context.
2023-03-04 18:06:20 -05:00
Andrew Clark faacefb4d0 Codemod tests to waitFor pattern (4/?) (#26302)
This converts some of our test suite to use the `waitFor` test pattern,
instead of the `expect(Scheduler).toFlushAndYield` pattern. Most of
these changes are automated with jscodeshift, with some slight manual
cleanup in certain cases.

See #26285 for full context.
2023-03-03 21:24:22 -05:00
Andrew Clark ce8a72fd4e Codemod tests to waitFor pattern (2/?) (#26296)
This converts some of our test suite to use the `waitFor` test pattern,
instead of the `expect(Scheduler).toFlushAndYield` pattern. Most of
these changes are automated with jscodeshift, with some slight manual
cleanup in certain cases.

See #26285 for full context.
2023-03-03 17:01:57 -05:00
Jan Kassens b2ae9ddb3b Cleanup enableSyncDefaultUpdate flag (#26236)
This feature flag is enabled everywhere.
2023-02-27 14:04:02 -05:00
Ming Ye 71cace4d32 Migrate testRunner from jasmine2 to jest-circus (#26144)
## Summary

In jest v27, jest-circus as default test runner
(https://github.com/facebook/jest/pull/10686)

## How did you test this change?

ci green
2023-02-10 13:39:14 -05:00
Ming Ye 55542bc73d Update jest printBasicPrototype config (#26142) 2023-02-10 09:58:57 +01:00
Ming Ye 35698311de Update jest escapeString config (#26140)
## Summary

In jest v29, snapshotFormat default to escapeString:
false(https://github.com/facebook/jest/pull/13036)

## How did you test this change?

ci green
2023-02-10 00:08:37 +01:00
Jan Kassens 6ddcbd4f96 [flow] enable LTI inference mode (#26104)
This is the next generation inference mode for Flow.
2023-02-09 17:07:39 -05:00
Sebastian Markbåge 01a0c4e12c Add Edge Server Builds for workerd / edge-light (#26116)
We currently abuse the browser builds for Web streams derived
environments. We already have a special build for Bun but we should also
have one for [other "edge"
runtimes](https://runtime-keys.proposal.wintercg.org/) so that we can
maximally take advantage of the APIs that exist on each platform.

In practice, we currently check for a global property called
`AsyncLocalStorage` in the server browser builds which we shouldn't
really do since browsers likely won't ever have it. Additionally, this
should probably move to an import which we can't add to actual browser
builds where that will be an invalid import. So it has to be a separate
build. That's not done yet in this PR but Vercel will follow
Cloudflare's lead here.

The `deno` key still points to the browser build since there's no
AsyncLocalStorage there but it could use this same or a custom build if
support is added.
2023-02-07 15:10:01 -05:00
Jan Kassens 2ef24145e4 [flow] upgrade to 0.199.0 (#26096)
`flow-remove-types` was also upgraded to the latest version.
2023-02-02 16:19:05 -05:00
Sebastian Markbåge 922dd7ba50 Revert the outer module object to an object (#26093)
This is because Webpack has a `typeof ... === 'object'` before its esm
compat test.

This is unfortunate because it means we can't have a nice error in CJS
when someone does this:

```
const fn = require('client-fn');
fn();
```

I also fixed some checks in the validator that read off the client ref.
It shouldn't do those checks against a client ref, since those now
throw.
2023-02-02 15:30:59 -05:00
Jan Kassens 6b30832666 Upgrade prettier (#26081)
The old version of prettier we were using didn't support the Flow syntax
to access properties in a type using `SomeType['prop']`. This updates
`prettier` and `rollup-plugin-prettier` to the latest versions.

I added the prettier config `arrowParens: "avoid"` to reduce the diff
size as the default has changed in Prettier 2.0. The largest amount of
changes comes from function expressions now having a space. This doesn't
have an option to preserve the old behavior, so we have to update this.
2023-01-31 08:25:05 -05:00
Jan Kassens 1f5ce59dd7 [cleanup] fully roll out warnAboutSpreadingKeyToJSX (#26080)
I fully enabled this flag internally now and unless I see complications,
we should be able to clean this up in the code.
2023-01-30 15:25:24 -05:00
Jan Kassens 0fce6bb498 [cleanup] remove feature flags warnAboutDefaultPropsOnFunctionComponents and warnAboutStringRefs (#25980)
These feature flags are fully rolled out and easy to clean up. Let's
remove them!
2023-01-11 12:19:46 -05:00
Jan Kassens c49131669b Remove unused Flow suppressions (#25977)
These suppressions are no longer required.

Generated using:
```sh
flow/tool update-suppressions .
```
followed by adding back 1 or 2 suppressions that were only triggered in
some configurations.
2023-01-10 10:32:42 -05:00
Jan Kassens e2424f33b3 [flow] enable exact_empty_objects (#25973)
This enables the "exact_empty_objects" setting for Flow which makes
empty objects exact instead of building up the type as properties are
added in code below. This is in preparation to Flow 191 which makes this
the default and removes the config.

More about the change in the Flow blog
[here](https://medium.com/flow-type/improved-handling-of-the-empty-object-in-flow-ead91887e40c).
2023-01-09 17:00:36 -05:00
Jan Kassens 0b4f443020 [flow] enable enforce_local_inference_annotations (#25921)
This setting is an incremental path to the next Flow version enforcing
type annotations on most functions (except some inline callbacks).

Used
```
node_modules/.bin/flow codemod annotate-functions-and-classes --write .
```
to add a majority of the types with some hand cleanup when for large
inferred objects that should just be `Fiber` or weird constructs
including `any`.

Suppressed the remaining issues.

Builds on #25918
2023-01-09 15:46:48 -05:00
Jan Kassens b83baf63f7 Transform updates to support Flow this annotation syntax (#25918)
Flow introduced a new syntax to annotated the context type of a
function, this tries to update the rest and add 1 example usage.

- 2b1fb91a55 already added the changes
required for eslint.
- Jest transform is updated to use the recommended `hermes-parser` which
can parse current and Flow syntax and will be updated in the future.
- Rollup uses a new plugin to strip the flow types. This isn't ideal as
the npm module is deprecated in favor of using `hermes-parser`, but I
couldn't figure out how to integrate that with Rollup.
2023-01-05 15:41:49 -05:00
Sebastian Markbåge 84a0a171ea Rename experimental useEvent to useEffectEvent (#25881)
We originally had grand plans for using this Event concept for more but
now it's only meant to be used in combination with effects.

It's an Event in the FRP terms, that is triggered from an Effect.
Technically it can also be from another function that itself is
triggered from an existing side-effect but that's kind of an advanced
case.

The canonical case is an effect that triggers an event:

```js
const onHappened = useEffectEvent(() => ...);
useEffect(() => {
  onHappened();
}, []);
```
2022-12-14 15:08:29 -05:00
Jan Kassens f101c2d0d3 Remove Reconciler fork (2/2) (#25775)
We've heard from multiple contributors that the Reconciler forking
mechanism was confusing and/or annoying to deal with. Since it's
currently unused and there's no immediate plans to start using it again,
this removes the forking.

Fully removing the fork is split into 2 steps to preserve file history:

**#25774 previous PR that did the bulk of the work:**
- remove `enableNewReconciler` feature flag.
- remove `unstable_isNewReconciler` export
- remove eslint rules for cross fork imports
- remove `*.new.js` files and update imports
- merge non-suffixed files into `*.old` files where both exist
(sometimes types were defined there)

**This PR**
- rename `*.old` files
2022-12-01 23:19:13 -05:00
Jan Kassens 420f0b7fa1 Remove Reconciler fork (1/2) (#25774)
We've heard from multiple contributors that the Reconciler forking
mechanism was confusing and/or annoying to deal with. Since it's
currently unused and there's no immediate plans to start using it again,
this removes the forking.

Fully removing the fork is split into 2 steps to preserve file history:

**This PR**
- remove `enableNewReconciler` feature flag.
- remove `unstable_isNewReconciler` export
- remove eslint rules for cross fork imports
- remove `*.new.js` files and update imports
- merge non-suffixed files into `*.old` files where both exist
(sometimes types were defined there)

**#25775**
- rename `*.old` files
2022-12-01 23:06:25 -05:00
Sebastian Silbermann 3ba7add608 Allow async blocks in to(Error|Warn)Dev (#25338) 2022-12-01 11:26:43 +01:00
Sebastian Silbermann 6fb8133ed3 Turn on string ref deprecation warning for everybody (not codemoddable) (#25383)
## Summary
 
Alternate to https://github.com/facebook/react/pull/25334 without any
prod runtime changes i.e. the proposed codemod in
https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#deprecate-string-refs-and-remove-production-mode-_owner-field
would not work.

## How did you test this change?

- [x] CI
- [x] `yarn test` with and without `warnAboutStringRefs`
2022-11-16 19:15:57 -05:00
Sebastian Markbåge 07f46ecf2e Turn on key spread warning in jsx-runtime for everyone (#25697)
This improves the error message a bit and ensures that we recommend
putting the key first, not last, which ensures that the faster
`jsx-runtime` is used.

This only affects the modern "automatic" JSX transform.
2022-11-16 18:57:50 -05:00
Andrew Clark 5450dd4098 Strict Mode: Reuse memoized result from first pass (#25583)
In Strict Mode, during development, user functions are double invoked to
help detect side effects. Currently, the way we implement this is to
completely discard the first pass and start over. Theoretically this
should be fine because components are idempotent. However, it's a bit
tricky to get right because our implementation (i.e. `renderWithHooks`)
is not completely idempotent with respect to internal data structures,
like the work-in-progress fiber. In the past we've had to be really
careful to avoid subtle bugs — for example, during the initial mount,
`setState` functions are bound to the particular hook instances that
were created during that render. If we compute new hook instances, we
must also compute new children, and they must correspond to each other.

This commit addresses a similar issue that came up related to `use`:
when something suspends, `use` reuses the promise that was passed during
the first attempt. This is itself a form of memoization. We need to be
able to memoize the reactive inputs to the `use` call using a hook (i.e.
`useMemo`), which means, the reactive inputs to `use` must come from the
same component invocation as the output.

The solution I've chosen is, rather than double invoke the entire
`renderWithHook` function, we should double invoke each individual user
function. It's a bit confusing but here's how it works:

We will invoke the entire component function twice. However, during the
second invocation of the component, the hook state from the first
invocation will be reused. That means things like `useMemo` functions
won't run again, because the deps will match and the memoized result
will be reused.

We want memoized functions to run twice, too, so account for this, user
functions are double invoked during the *first* invocation of the
component function, and are *not* double invoked during the second
incovation:

- First execution of component function: user functions are double
invoked
- Second execution of component function (in Strict Mode, during
development): user functions are not double invoked.

It's hard to explain verbally but much clearer when you run the test
cases I've added.
2022-10-28 17:46:20 -04:00
Sebastian Markbåge 28a574ea8f Try assigning fetch to globalThis if global assignment fails (#25571)
In case it's a more modern yet rigid environment.
2022-10-27 02:43:17 -04:00
Sebastian Markbåge e7c5af45ce Update cache() and use() to the canary aka next channel (#25502)
Testing what it would look like to move this to the `next` channel.
2022-10-23 23:20:52 -04:00
Sebastian Markbåge 1d3fc9c9c4 Bug fix when resolving cache (#25545)
We must use the asynclocalstorage one if it's available.
2022-10-23 14:12:47 -04:00
Sebastian Markbåge cce18e3504 [Flight] Use AsyncLocalStorage to extend the scope of the cache to micro tasks (#25542)
This extends the scope of the cache and fetch instrumentation using
AsyncLocalStorage for microtasks. This is an intermediate step. It sets
up the dispatcher only once. This is unique to RSC because it uses the
react.shared-subset module for its shared state.

Ideally we should support multiple renderers. We should also have this
take over from an outer SSR's instrumented fetch. We should also be able
to have a fallback to global state per request where AsyncLocalStorage
doesn't exist and then the whole client-side solutions. I'm still
figuring out the right wiring for that so this is a temporary hack.
2022-10-23 01:06:58 -04:00
Sebastian Markbåge caa84c8da0 Revert fetch instrumentation to only RSC (#25540)
Revert fetch instrumentation so that it only affects RSC by applying it
only in the react-server condition of "react".

This helps make the rollout a little smoother because these affects
existing libraries that fetch during client components, and then gets
forever cached. We need to implement the GC first.

I haven't fully implemented the SSR part anyway.

The main problem that we discovered is that `"react"` and
`"react/react.shared-subset"` have separate dispatchers in an
environment that runs both Fizz and Flight. That's intentional and
sometimes a feature. However, in this case it means that we instrument
fetch twice and when you run Flight inside Fizz, that fetch goes into
both caches when it's supposed to only see the inner one. I'm not sure
how to solve that atm.
2022-10-22 22:58:30 -04:00
Sebastian Markbåge 79c5829813 Let ReactDOM initialize in RSC (#25503)
With the `react-dom/server-rendering-stub` you can import `react-dom` in
RSC so that you can call `preload` and `preinit` but if you don't alias
it, then requiring it breaks because we React.Component which doesn't
exist in the react subset.
2022-10-21 10:41:14 -04:00
Andrew Clark c635807875 Support use in act testing API (#25523)
`use` can avoid suspending on already resolved data by yielding to
microtasks. In a real, browser environment, we do this by scheduling a
platform task (i.e. postTask).

In a test environment, tasks are scheduled on a special internal queue
so that they can be flushed by the `act` testing API. So we need to add
support for this in `act`.

This behavior only works if you `await` the thenable returned by the
`act` call. We currently do not require that users do this. So I added a
warning, but it only fires if `use` was called. The old Suspense pattern
will not trigger a warning. This is to avoid breaking existing tests
that use Suspense.

The implementation of `act` has gotten extremely complicated because of
the subtle changes in behavior over the years, and our commitment to
maintaining backwards compatibility. We really should consider being
more restrictive in a future major release.

The changes are a bit confusing so I did my best to add inline comments
explaining how it works.

## Test plan

I ran this against Facebook's internal Jest test suite to confirm
nothing broke
2022-10-20 22:08:23 -04:00