mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
c4d4bc18c19e60e4016b52bd43a7045c1940053e
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f5a54b1e75 |
[ez] Remove trailing space from babel-refresh header
ghstack-source-id: |
||
|
|
d1fee4a2fe |
[ez] Add noformat etc headers into some files
These are only needed internally so I'm opting to just do it in the commit artifacts job instead of amending the build config. ghstack-source-id: |
||
|
|
fcd14111f7 |
Minify DEV bundles with closure (#29809)
The goal is to improve speed of the development by inlining and DCE
unused branches.
We have the ability to preserve some variable names and pretty print in
the production version so might as well do the same with DEV.
DiffTrain build for [
|
||
|
|
01f55b75d9 |
Add React.useActionState (#28491)
## Overview
_Depends on https://github.com/facebook/react/pull/28514_
This PR adds a new React hook called `useActionState` to replace and
improve the ReactDOM `useFormState` hook.
## Motivation
This hook intends to fix some of the confusion and limitations of the
`useFormState` hook.
The `useFormState` hook is only exported from the `ReactDOM` package and
implies that it is used only for the state of `<form>` actions, similar
to `useFormStatus` (which is only for `<form>` element status). This
leads to understandable confusion about why `useFormState` does not
provide a `pending` state value like `useFormStatus` does.
The key insight is that the `useFormState` hook does not actually return
the state of any particular form at all. Instead, it returns the state
of the _action_ passed to the hook, wrapping it and returning a
trackable action to add to a form, and returning the last returned value
of the action given. In fact, `useFormState` doesn't need to be used in
a `<form>` at all.
Thus, adding a `pending` value to `useFormState` as-is would thus be
confusing because it would only return the pending state of the _action_
given, not the `<form>` the action is passed to. Even if we wanted to
tie them together, the returned `action` can be passed to multiple
forms, creating confusing and conflicting pending states during multiple
form submissions.
Additionally, since the action is not related to any particular
`<form>`, the hook can be used in any renderer - not only `react-dom`.
For example, React Native could use the hook to wrap an action, pass it
to a component that will unwrap it, and return the form result state and
pending state. It's renderer agnostic.
To fix these issues, this PR:
- Renames `useFormState` to `useActionState`
- Adds a `pending` state to the returned tuple
- Moves the hook to the `'react'` package
## Reference
The `useFormState` hook allows you to track the pending state and return
value of a function (called an "action"). The function passed can be a
plain JavaScript client function, or a bound server action to a
reference on the server. It accepts an optional `initialState` value
used for the initial render, and an optional `permalink` argument for
renderer specific pre-hydration handling (such as a URL to support
progressive hydration in `react-dom`).
Type:
```ts
function useActionState<State>(
action: (state: Awaited<State>) => State | Promise<State>,
initialState: Awaited<State>,
permalink?: string,
): [state: Awaited<State>, dispatch: () => void, boolean];
```
The hook returns a tuple with:
- `state`: the last state the action returned
- `dispatch`: the method to call to dispatch the wrapped action
- `pending`: the pending state of the action and any state updates
contained
Notably, state updates inside of the action dispatched are wrapped in a
transition to keep the page responsive while the action is completing
and the UI is updated based on the result.
## Usage
The `useActionState` hook can be used similar to `useFormState`:
```js
import { useActionState } from "react"; // not react-dom
function Form({ formAction }) {
const [state, action, isPending] = useActionState(formAction);
return (
<form action={action}>
<input type="email" name="email" disabled={isPending} />
<button type="submit" disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</form>
);
}
```
But it doesn't need to be used with a `<form/>` (neither did
`useFormState`, hence the confusion):
```js
import { useActionState, useRef } from "react";
function Form({ someAction }) {
const ref = useRef(null);
const [state, action, isPending] = useActionState(someAction);
async function handleSubmit() {
// See caveats below
await action({ email: ref.current.value });
}
return (
<div>
<input ref={ref} type="email" name="email" disabled={isPending} />
<button onClick={handleSubmit} disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</div>
);
}
```
## Benefits
One of the benefits of using this hook is the automatic tracking of the
return value and pending states of the wrapped function. For example,
the above example could be accomplished via:
```js
import { useActionState, useRef } from "react";
function Form({ someAction }) {
const ref = useRef(null);
const [state, setState] = useState(null);
const [isPending, setIsPending] = useTransition();
function handleSubmit() {
startTransition(async () => {
const response = await someAction({ email: ref.current.value });
setState(response);
});
}
return (
<div>
<input ref={ref} type="email" name="email" disabled={isPending} />
<button onClick={handleSubmit} disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</div>
);
}
```
However, this hook adds more benefits when used with render specific
elements like react-dom `<form>` elements and Server Action. With
`<form>` elements, React will automatically support replay actions on
the form if it is submitted before hydration has completed, providing a
form of partial progressive enhancement: enhancement for when javascript
is enabled but not ready.
Additionally, with the `permalink` argument and Server Actions,
frameworks can provide full progressive enhancement support, submitting
the form to the URL provided along with the FormData from the form. On
submission, the Server Action will be called during the MPA navigation,
similar to any raw HTML app, server rendered, and the result returned to
the client without any JavaScript on the client.
## Caveats
There are a few Caveats to this new hook:
**Additional state update**: Since we cannot know whether you use the
pending state value returned by the hook, the hook will always set the
`isPending` state at the beginning of the first chained action,
resulting in an additional state update similar to `useTransition`. In
the future a type-aware compiler could optimize this for when the
pending state is not accessed.
**Pending state is for the action, not the handler**: The difference is
subtle but important, the pending state begins when the return action is
dispatched and will revert back after all actions and transitions have
settled. The mechanism for this under the hook is the same as
useOptimisitic.
Concretely, what this means is that the pending state of
`useActionState` will not represent any actions or sync work performed
before dispatching the action returned by `useActionState`. Hopefully
this is obvious based on the name and shape of the API, but there may be
some temporary confusion.
As an example, let's take the above example and await another action
inside of it:
```js
import { useActionState, useRef } from "react";
function Form({ someAction, someOtherAction }) {
const ref = useRef(null);
const [state, action, isPending] = useActionState(someAction);
async function handleSubmit() {
await someOtherAction();
// The pending state does not start until this call.
await action({ email: ref.current.value });
}
return (
<div>
<input ref={ref} type="email" name="email" disabled={isPending} />
<button onClick={handleSubmit} disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</div>
);
}
```
Since the pending state is related to the action, and not the handler or
form it's attached to, the pending state only changes when the action is
dispatched. To solve, there are two options.
First (recommended): place the other function call inside of the action
passed to `useActionState`:
```js
import { useActionState, useRef } from "react";
function Form({ someAction, someOtherAction }) {
const ref = useRef(null);
const [state, action, isPending] = useActionState(async (data) => {
// Pending state is true already.
await someOtherAction();
return someAction(data);
});
async function handleSubmit() {
// The pending state starts at this call.
await action({ email: ref.current.value });
}
return (
<div>
<input ref={ref} type="email" name="email" disabled={isPending} />
<button onClick={handleSubmit} disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</div>
);
}
```
For greater control, you can also wrap both in a transition and use the
`isPending` state of the transition:
```js
import { useActionState, useTransition, useRef } from "react";
function Form({ someAction, someOtherAction }) {
const ref = useRef(null);
// isPending is used from the transition wrapping both action calls.
const [isPending, startTransition] = useTransition();
// isPending not used from the individual action.
const [state, action] = useActionState(someAction);
async function handleSubmit() {
startTransition(async () => {
// The transition pending state has begun.
await someOtherAction();
await action({ email: ref.current.value });
});
}
return (
<div>
<input ref={ref} type="email" name="email" disabled={isPending} />
<button onClick={handleSubmit} disabled={isPending}>
Submit
</button>
{state.errorMessage && <p>{state.errorMessage}</p>}
</div>
);
}
```
A similar technique using `useOptimistic` is preferred over using
`useTransition` directly, and is left as an exercise to the reader.
## Thanks
Thanks to @ryanflorence @mjackson @wesbos
(https://github.com/facebook/react/issues/27980#issuecomment-1960685940)
and [Allan
Lasser](https://allanlasser.com/posts/2024-01-26-avoid-using-reacts-useformstatus)
for their feedback and suggestions on `useFormStatus` hook.
DiffTrain build for [
|
||
|
|
d1b0b96c04 |
[Fresh] Update the list of built-in hooks (#27864)
DiffTrain build for [
|
||
|
|
7b76862985 |
Update Rollup and related plugins to their most recent versions (#24916)
Update Rollup and related plugins to their most recent versions +
resolve any breaking changes/deprecations/etc along the way. I made each
change piece by piece, so the commit history tells a pretty good story
of what was changed where/how/why.
fixes https://github.com/facebook/react/issues/24894
For the full deepdive/context, see:
- https://github.com/facebook/react/issues/24894
The inspiration for this came from @jasonwilliams 's PR for attempting
to add sourcemap output support to React's builds:
- https://github.com/facebook/react/issues/20186
- https://github.com/facebook/react/pull/21946
But I figured that it would be useful to minimise the scope of changes
in that PR, and to modernise the build tooling along the way.
If any of these updates rely on a node version later than `10.x`, then
the following PR may have to land first, otherwise things might break on
AppVeyor:
- https://github.com/facebook/react/issues/24891
- https://github.com/facebook/react/pull/24892
Co-authored-by: Sebastian Markbage <sebastian@calyptus.eu>
DiffTrain build for [
|
||
|
|
2b6133e035 |
[DiffTrain] Strip @license from files (#25821)
We need to remove this for some internal tests. This was previously in our upgrade script so adding it back here for parity. Test plan: files were updated correctly [[1]](https://github.com/facebook/react/commit/1704bbb8268345bf7aa405101313b3639e03e221#diff-80b968e05ce2ceeff6e17c938dc722aff2c1c660f8ef402e6664bc5b2cafa5fbL2) [[2]](https://github.com/facebook/react/commit/1704bbb8268345bf7aa405101313b3639e03e221#diff-6ecd07a61c8e0e28793dace3f9f62751e4808de9c2965aa1ddeb0157f3c9b4ecL2) Co-authored-by: Jan Kassens <jkassens@meta.com> DiffTrain build for `7c39922891bf8e0ce179a78a373a61b3afe3c1c7` |
||
|
|
30bcb2a2eb |
Bump qs from 6.4.0 to 6.4.1 in /fixtures/attribute-behavior (#25820)
Bumps [qs](https://github.com/ljharb/qs) from 6.4.0 to 6.4.1. <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/ljharb/qs/blob/main/CHANGELOG.md">qs's changelog</a>.</em></p> <blockquote> <h2><strong>6.4.1</strong></h2> <ul> <li>[Fix] <code>parse</code>: ignore <code>__proto__</code> keys (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/428">#428</a>)</li> <li>[Fix] fix for an impossible situation: when the formatter is called with a non-string value</li> <li>[Fix] use <code>safer-buffer</code> instead of <code>Buffer</code> constructor</li> <li>[Fix] <code>utils.merge</code>: avoid a crash with a null target and an array source</li> <li>[Fix]<code> </code>utils.merge`: avoid a crash with a null target and a truthy non-array source</li> <li>[Fix] <code>stringify</code>: fix a crash with <code>strictNullHandling</code> and a custom <code>filter</code>/<code>serializeDate</code> (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/279">#279</a>)</li> <li>[Fix] <code>utils</code>: <code>merge</code>: fix crash when <code>source</code> is a truthy primitive & no options are provided</li> <li>[Fix] when <code>parseArrays</code> is false, properly handle keys ending in <code>[]</code></li> <li>[Robustness] <code>stringify</code>: avoid relying on a global <code>undefined</code> (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/427">#427</a>)</li> <li>[Refactor] use cached <code>Array.isArray</code></li> <li>[Refactor] <code>stringify</code>: Avoid arr = arr.concat(...), push to the existing instance (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/269">#269</a>)</li> <li>[readme] remove travis badge; add github actions/codecov badges; update URLs</li> <li>[Docs] Clarify the need for "arrayLimit" option</li> <li>[meta] fix README.md (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/399">#399</a>)</li> <li>[meta] Clean up license text so it’s properly detected as BSD-3-Clause</li> <li>[meta] add FUNDING.yml</li> <li>[actions] backport actions from main</li> <li>[Tests] remove nonexistent tape option</li> <li>[Dev Deps] backport from main</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/ljharb/qs/commit/486aa46547b4e878d6e87183de95dd26d46fb020"><code>486aa46</code></a> v6.4.1</li> <li><a href="https://github.com/ljharb/qs/commit/727ef5d34605108acb3513f72d5435972ed15b68"><code>727ef5d</code></a> [Fix] <code>parse</code>: ignore <code>__proto__</code> keys (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/428">#428</a>)</li> <li><a href="https://github.com/ljharb/qs/commit/cd1874eb179950de3f5b32e708b4a3a2d0619501"><code>cd1874e</code></a> [Robustness] <code>stringify</code>: avoid relying on a global <code>undefined</code> (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/427">#427</a>)</li> <li><a href="https://github.com/ljharb/qs/commit/45e987c6038db47199a560294c20a67da9ab49e3"><code>45e987c</code></a> [readme] remove travis badge; add github actions/codecov badges; update URLs</li> <li><a href="https://github.com/ljharb/qs/commit/90a3bced518c6ff4a97919d10de9498fea961acf"><code>90a3bce</code></a> [meta] fix README.md (<a href="https://github-redirect.dependabot.com/ljharb/qs/issues/399">#399</a>)</li> <li><a href="https://github.com/ljharb/qs/commit/9566d25019caae8c4f1a9097bf344238a583d014"><code>9566d25</code></a> [Fix] fix for an impossible situation: when the formatter is called with a no...</li> <li><a href="https://github.com/ljharb/qs/commit/74227ef022282881f41d37d65adba5d399d2b33a"><code>74227ef</code></a> Clean up license text so it’s properly detected as BSD-3-Clause</li> <li><a href="https://github.com/ljharb/qs/commit/35dfb227e274367e163b3d943fc975f95448685a"><code>35dfb22</code></a> [actions] backport actions from main</li> <li><a href="https://github.com/ljharb/qs/commit/7d4670fca6ed46a1fc6237bccffe0ea82a641411"><code>7d4670f</code></a> [Dev Deps] backport from main</li> <li><a href="https://github.com/ljharb/qs/commit/0485440902d3fc03d1d973d91af5a183fa4e3059"><code>0485440</code></a> [Fix] use <code>safer-buffer</code> instead of <code>Buffer</code> constructor</li> <li>Additional commits viewable in <a href="https://github.com/ljharb/qs/compare/v6.4.0...v6.4.1">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/facebook/react/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> DiffTrain build for `2f16409f3a40de334973abdcba08e09284ed1c9d` |
||
|
|
1704bbb826 |
[DiffTrain] Strip @license from files
DiffTrain build for `29bb7f8a2fbdbb5d8a6e95c4ba6221d9c50d23af` |
||
|
|
1672d0da73 |
Build for 62e2b1374b
|