Skip to content

Commit ab1c455

Browse files
docs(en): merge reactjs.org/main into zh-hans.reactjs.org/main @ 10574e5 (#1345)
2 parents 8173247 + 9784de7 commit ab1c455

File tree

3 files changed

+320
-0
lines changed

3 files changed

+320
-0
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: "React DOM Hooks"
3+
---
4+
5+
<Intro>
6+
7+
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.
8+
9+
</Intro>
10+
11+
---
12+
13+
## Form Hooks {/*form-hooks*/}
14+
15+
<Canary>
16+
17+
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).
18+
19+
</Canary>
20+
21+
*Forms* let you create interactive controls for submitting information. To manage forms in your components, use one of these Hooks:
22+
23+
* [`useFormStatus`](/reference/react-dom/hooks/useFormStatus) allows you to make updates to the UI based on the status of the a form.
24+
* `useFormState` allows you to manage state inside a form.
25+
26+
```js
27+
function Form({ action }) {
28+
async function increment(n) {
29+
return n + 1;
30+
}
31+
const [count, incrementFormAction] = useFormState(increment, 0);
32+
return (
33+
<form action={action}>
34+
<button formAction={incrementFormAction}>Count: {count}</button>
35+
<Button />
36+
</form>
37+
);
38+
}
39+
40+
function Button() {
41+
const { pending } = useFormStatus();
42+
return (
43+
<button disabled={pending} type="submit">
44+
Submit
45+
</button>
46+
);
47+
}
48+
```
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
---
2+
title: useFormStatus
3+
canary: true
4+
---
5+
6+
<Canary>
7+
8+
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).
9+
10+
</Canary>
11+
12+
<Intro>
13+
14+
`useFormStatus` is a Hook that gives you status information of the last form submission.
15+
16+
```js
17+
const { pending, data, method, action } = useFormStatus();
18+
```
19+
20+
</Intro>
21+
22+
<InlineToc />
23+
24+
---
25+
26+
## Reference {/*reference*/}
27+
28+
### `useFormStatus()` {/*use-form-status*/}
29+
30+
The `useFormStatus` Hook provides status information of the last form submission.
31+
32+
```js {5},[[1, 6, "status.pending"]]
33+
import { useFormStatus } from "react-dom";
34+
import action from './actions';
35+
36+
function Submit() {
37+
const status = useFormStatus();
38+
return <button disabled={status.pending}>Submit</button>
39+
}
40+
41+
export default App() {
42+
return (
43+
<form action={action}>
44+
<Submit />
45+
</form>
46+
);
47+
}
48+
```
49+
50+
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.
51+
52+
In the above example, `Submit` uses this information to disable `<button>` presses while the form is submitting.
53+
54+
[See more examples below.](#usage)
55+
56+
#### Parameters {/*parameters*/}
57+
58+
`useFormStatus` does not take any parameters.
59+
60+
#### Returns {/*returns*/}
61+
62+
A `status` object with the following properties:
63+
64+
* `pending`: A boolean. If `true`, this means the parent `<form>` is pending submission. Otherwise, `false`.
65+
66+
* `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`.
67+
68+
* `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.
69+
70+
[//]: # (Link to `<form>` documentation. "Read more on the `action` prop on `<form>`.")
71+
* `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`.
72+
73+
#### Caveats {/*caveats*/}
74+
75+
* The `useFormStatus` Hook must be called from a component that is rendered inside a `<form>`.
76+
* `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.
77+
78+
---
79+
80+
## Usage {/*usage*/}
81+
82+
### Display a pending state during form submission {/*display-a-pending-state-during-form-submission*/}
83+
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.
84+
85+
Here, we use the `pending` property to indicate the form is submitting.
86+
87+
<Sandpack>
88+
89+
```js App.js
90+
import { useFormStatus } from "react-dom";
91+
import { submitForm } from "./actions.js";
92+
93+
function Submit() {
94+
const { pending } = useFormStatus();
95+
return (
96+
<button type="submit" disabled={pending}>
97+
{pending ? "Submitting..." : "Submit"}
98+
</button>
99+
);
100+
}
101+
102+
function Form({ action }) {
103+
return (
104+
<form action={action}>
105+
<Submit />
106+
</form>
107+
);
108+
}
109+
110+
export default function App() {
111+
return <Form action={submitForm} />;
112+
}
113+
```
114+
115+
```js actions.js hidden
116+
export async function submitForm(query) {
117+
await new Promise((res) => setTimeout(res, 1000));
118+
}
119+
```
120+
121+
```json package.json hidden
122+
{
123+
"dependencies": {
124+
"react": "canary",
125+
"react-dom": "canary",
126+
"react-scripts": "^5.0.0"
127+
},
128+
"main": "/index.js",
129+
"devDependencies": {}
130+
}
131+
```
132+
</Sandpack>
133+
134+
<Pitfall>
135+
136+
##### `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*/}
137+
138+
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.
139+
140+
```js
141+
function Form() {
142+
// 🚩 `pending` will never be true
143+
// useFormStatus does not track the form rendered in this component
144+
const { pending } = useFormStatus();
145+
return <form action={submit}></form>;
146+
}
147+
```
148+
149+
Instead call `useFormStatus` from inside a component that is located inside `<form>`.
150+
151+
```js
152+
function Submit() {
153+
// ✅ `pending` will be derived from the form that wraps the Submit component
154+
const { pending } = useFormStatus();
155+
return <button disabled={pending}>...</button>;
156+
}
157+
158+
function Form() {
159+
// This is the <form> `useFormStatus` tracks
160+
return (
161+
<form action={submit}>
162+
<Submit />
163+
</form>
164+
);
165+
}
166+
```
167+
168+
</Pitfall>
169+
170+
### Read the form data being submitted {/*read-form-data-being-submitted*/}
171+
172+
You can use the `data` property of the status information returned from `useFormStatus` to display what data is being submitted by the user.
173+
174+
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.
175+
176+
<Sandpack>
177+
178+
```js UsernameForm.js active
179+
import {useState, useMemo, useRef} from 'react';
180+
import {useFormStatus} from 'react-dom';
181+
182+
export default function UsernameForm() {
183+
const {pending, data} = useFormStatus();
184+
185+
const [showSubmitted, setShowSubmitted] = useState(false);
186+
const submittedUsername = useRef(null);
187+
const timeoutId = useRef(null);
188+
189+
useMemo(() => {
190+
if (pending) {
191+
submittedUsername.current = data?.get('username');
192+
if (timeoutId.current != null) {
193+
clearTimeout(timeoutId.current);
194+
}
195+
196+
timeoutId.current = setTimeout(() => {
197+
timeoutId.current = null;
198+
setShowSubmitted(false);
199+
}, 2000);
200+
setShowSubmitted(true);
201+
}
202+
}, [pending, data]);
203+
204+
return (
205+
<>
206+
<label>Request a Username: </label><br />
207+
<input type="text" name="username" />
208+
<button type="submit" disabled={pending}>
209+
{pending ? 'Submitting...' : 'Submit'}
210+
</button>
211+
{showSubmitted ? (
212+
<p>Submitted request for username: {submittedUsername.current}</p>
213+
) : null}
214+
</>
215+
);
216+
}
217+
```
218+
219+
```js App.js
220+
import UsernameForm from './UsernameForm';
221+
import { submitForm } from "./actions.js";
222+
223+
export default function App() {
224+
return (
225+
<form action={submitForm}>
226+
<UsernameForm />
227+
</form>
228+
);
229+
}
230+
```
231+
232+
```js actions.js hidden
233+
export async function submitForm(query) {
234+
await new Promise((res) => setTimeout(res, 1000));
235+
}
236+
```
237+
238+
```json package.json hidden
239+
{
240+
"dependencies": {
241+
"react": "canary",
242+
"react-dom": "canary",
243+
"react-scripts": "^5.0.0"
244+
},
245+
"main": "/index.js",
246+
"devDependencies": {}
247+
}
248+
```
249+
</Sandpack>
250+
251+
---
252+
253+
## Troubleshooting {/*troubleshooting*/}
254+
255+
### `status.pending` is never `true` {/*pending-is-never-true*/}
256+
257+
`useFormStatus` will only return status information for a parent `<form>`.
258+
259+
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.
260+
261+
`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.

src/sidebarReference.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,17 @@
161161
"hasSectionHeader": true,
162162
"sectionHeader": "[email protected]"
163163
},
164+
{
165+
"title": "Hook",
166+
"path": "/reference/react-dom/hooks",
167+
"routes": [
168+
{
169+
"title": "useFormStatus",
170+
"path": "/reference/react-dom/hooks/useFormStatus",
171+
"canary": true
172+
}
173+
]
174+
},
164175
{
165176
"title": "组件",
166177
"path": "/reference/react-dom/components",

0 commit comments

Comments
 (0)