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

docs(en): merge reactjs.org/main into zh-hans.reactjs.org/main @ 10574e59 #1345

Merged
merged 6 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/content/reference/react-dom/hooks/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: "React DOM Hooks"
---

<Intro>

The `react-dom` package contains Hooks that are only supported for web applications (which run in the browser DOM environment). These Hooks are not supported in non-browser environments like iOS, Android, or Windows applications. If you are looking for Hooks that are supported in web browsers *and other environments* see [the React Hooks page](/reference/react). This page lists all the Hooks in the `react-dom` package.

</Intro>

---

## Form Hooks {/*form-hooks*/}

<Canary>

Form Hooks are currently only available in React's canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).

</Canary>

*Forms* let you create interactive controls for submitting information. To manage forms in your components, use one of these Hooks:

* [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) allows you to make updates to the UI based on the status of the a form.
* `useFormState` allows you to manage state inside a form.

```js
function Form({ action }) {
async function increment(n) {
return n + 1;
}
const [count, incrementFormAction] = useFormState(increment, 0);
return (
<form action={action}>
<button formAction={incrementFormAction}>Count: {count}</button>
<Button />
</form>
);
}

function Button() {
const { pending } = useFormStatus();
return (
<button disabled={pending} type="submit">
Submit
</button>
);
}
```
261 changes: 261 additions & 0 deletions src/content/reference/react-dom/hooks/useFormStatus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
---
title: useFormStatus
canary: true
---

<Canary>

The `useFormStatus` Hook is currently only available in React's canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels).

</Canary>

<Intro>

`useFormStatus` is a Hook that gives you status information of the last form submission.

```js
const { pending, data, method, action } = useFormStatus();
```

</Intro>

<InlineToc />

---

## Reference {/*reference*/}

### `useFormStatus()` {/*use-form-status*/}

The `useFormStatus` Hook provides status information of the last form submission.

```js {5},[[1, 6, "status.pending"]]
import { useFormStatus } from "react-dom";
import action from './actions';

function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}

export default App() {
return (
<form action={action}>
<Submit />
</form>
);
}
```

To get status information, the `Submit` component must be rendered within a `<form>`. The Hook returns information like the <CodeStep step={1}>`pending`</CodeStep> property which tells you if the form is actively submitting.

In the above example, `Submit` uses this information to disable `<button>` presses while the form is submitting.

[See more examples below.](#usage)

#### Parameters {/*parameters*/}

`useFormStatus` does not take any parameters.

#### Returns {/*returns*/}

A `status` object with the following properties:

* `pending`: A boolean. If `true`, this means the parent `<form>` is pending submission. Otherwise, `false`.

* `data`: An object implementing the [`FormData interface`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) that contains the data the parent `<form>` is submitting. If there is no active submission or no parent `<form>`, it will be `null`.

* `method`: A string value of either `'get'` or `'post'`. This represents whether the parent `<form>` is submitting with either a `GET` or `POST` [HTTP method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods). By default, a `<form>` will use the `GET` method and can be specified by the [`method`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#method) property.

[//]: # (Link to `<form>` documentation. "Read more on the `action` prop on `<form>`.")
* `action`: A reference to the function passed to the `action` prop on the parent `<form>`. If there is no parent `<form>`, the property is `null`. If there is a URI value provided to the `action` prop, or no `action` prop specified, `status.action` will be `null`.

#### Caveats {/*caveats*/}

* The `useFormStatus` Hook must be called from a component that is rendered inside a `<form>`.
* `useFormStatus` will only return status information for a parent `<form>`. It will not return status information for any `<form>` rendered in that same component or children components.

---

## Usage {/*usage*/}

### Display a pending state during form submission {/*display-a-pending-state-during-form-submission*/}
To display a pending state while a form is submitting, you can call the `useFormStatus` Hook in a component rendered in a `<form>` and read the `pending` property returned.

Here, we use the `pending` property to indicate the form is submitting.

<Sandpack>

```js App.js
import { useFormStatus } from "react-dom";
import { submitForm } from "./actions.js";

function Submit() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
{pending ? "Submitting..." : "Submit"}
</button>
);
}

function Form({ action }) {
return (
<form action={action}>
<Submit />
</form>
);
}

export default function App() {
return <Form action={submitForm} />;
}
```

```js actions.js hidden
export async function submitForm(query) {
await new Promise((res) => setTimeout(res, 1000));
}
```

```json package.json hidden
{
"dependencies": {
"react": "canary",
"react-dom": "canary",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
```
</Sandpack>

<Pitfall>

##### `useFormStatus` will not return status information for a `<form>` rendered in the same component. {/*useformstatus-will-not-return-status-information-for-a-form-rendered-in-the-same-component*/}

The `useFormStatus` Hook only returns status information for a parent `<form>` and not for any `<form>` rendered in the same component calling the Hook, or child components.

```js
function Form() {
// 🚩 `pending` will never be true
// useFormStatus does not track the form rendered in this component
const { pending } = useFormStatus();
return <form action={submit}></form>;
}
```

Instead call `useFormStatus` from inside a component that is located inside `<form>`.

```js
function Submit() {
// ✅ `pending` will be derived from the form that wraps the Submit component
const { pending } = useFormStatus();
return <button disabled={pending}>...</button>;
}

function Form() {
// This is the <form> `useFormStatus` tracks
return (
<form action={submit}>
<Submit />
</form>
);
}
```

</Pitfall>

### Read the form data being submitted {/*read-form-data-being-submitted*/}

You can use the `data` property of the status information returned from `useFormStatus` to display what data is being submitted by the user.

Here, we have a form where users can request a username. We can use `useFormStatus` to display a temporary status message confirming what username they have requested.

<Sandpack>

```js UsernameForm.js active
import {useState, useMemo, useRef} from 'react';
import {useFormStatus} from 'react-dom';

export default function UsernameForm() {
const {pending, data} = useFormStatus();

const [showSubmitted, setShowSubmitted] = useState(false);
const submittedUsername = useRef(null);
const timeoutId = useRef(null);

useMemo(() => {
if (pending) {
submittedUsername.current = data?.get('username');
if (timeoutId.current != null) {
clearTimeout(timeoutId.current);
}

timeoutId.current = setTimeout(() => {
timeoutId.current = null;
setShowSubmitted(false);
}, 2000);
setShowSubmitted(true);
}
}, [pending, data]);

return (
<>
<label>Request a Username: </label><br />
<input type="text" name="username" />
<button type="submit" disabled={pending}>
{pending ? 'Submitting...' : 'Submit'}
</button>
{showSubmitted ? (
<p>Submitted request for username: {submittedUsername.current}</p>
) : null}
</>
);
}
```

```js App.js
import UsernameForm from './UsernameForm';
import { submitForm } from "./actions.js";

export default function App() {
return (
<form action={submitForm}>
<UsernameForm />
</form>
);
}
```

```js actions.js hidden
export async function submitForm(query) {
await new Promise((res) => setTimeout(res, 1000));
}
```

```json package.json hidden
{
"dependencies": {
"react": "canary",
"react-dom": "canary",
"react-scripts": "^5.0.0"
},
"main": "/index.js",
"devDependencies": {}
}
```
</Sandpack>

---

## Troubleshooting {/*troubleshooting*/}

### `status.pending` is never `true` {/*pending-is-never-true*/}

`useFormStatus` will only return status information for a parent `<form>`.

If the component that calls `useFormStatus` is not nested in a `<form>`, `status.pending` will always return `false`. Verify `useFormStatus` is called in a component that is a child of a `<form>` element.

`useFormStatus` will not track the status of a `<form>` rendered in the same component. See [Pitfall](#useformstatus-will-not-return-status-information-for-a-form-rendered-in-the-same-component) for more details.
11 changes: 11 additions & 0 deletions src/sidebarReference.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@
"hasSectionHeader": true,
"sectionHeader": "[email protected]"
},
{
"title": "Hook",
"path": "/reference/react-dom/hooks",
"routes": [
{
"title": "useFormStatus",
"path": "/reference/react-dom/hooks/useFormStatus",
"canary": true
}
]
},
{
"title": "组件",
"path": "/reference/react-dom/components",
Expand Down
Loading