Skip to content
Draft
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
4 changes: 2 additions & 2 deletions src/content/reference/react/startTransition.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ function TabContainer() {

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

* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). React calls `action` immediately with no parameters and marks all state updates scheduled synchronously during the `action` function call as Transitions. Any async calls awaited in the `action` will be included in the transition, but currently require wrapping any `set` functions after the `await` in an additional `startTransition` (see [Troubleshooting](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition)). State updates marked as Transitions will be [non-blocking](#marking-a-state-update-as-a-non-blocking-transition) and [will not display unwanted loading indicators.](/reference/react/useTransition#preventing-unwanted-loading-indicators).
* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). The function can be synchronous or asynchronous. React calls `action` immediately with no parameters and marks all state updates scheduled during the `action` as Transitions. State updates marked as Transitions will be [non-blocking](#marking-a-state-update-as-a-non-blocking-transition) and [will not display unwanted loading indicators.](/reference/react/useTransition#preventing-unwanted-loading-indicators). If you need to track a pending Transition, use [`useTransition`](/reference/react/useTransition) instead.

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

Expand All @@ -55,7 +55,7 @@ function TabContainer() {

* The function you pass to `startTransition` is called immediately, marking all state updates that happen while it executes as Transitions. If you try to perform state updates in a `setTimeout`, for example, they won't be marked as Transitions.

* You must wrap any state updates after any async requests in another `startTransition` to mark them as Transitions. This is a known limitation that we will fix in the future (see [Troubleshooting](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition)).
* When using the standalone `startTransition` function, state updates after `await` are not automatically marked as Transitions. Wrap them in another `startTransition` call (see [Troubleshooting](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition)). If you use [`useTransition`](/reference/react/useTransition) in React 19, the `startTransition` function it returns supports async Actions, and state updates after `await` are included in the Transition automatically.

* A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input state update.

Expand Down
2 changes: 1 addition & 1 deletion src/content/reference/react/useActionState.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Each time you call `dispatchAction`, React calls the `reducerAction` with the `a
* `reducerAction` can be sync or async. It can perform sync actions like showing a notification, or async actions like posting updates to a server.
* `reducerAction` is not invoked twice in `<StrictMode>` since `reducerAction` is designed to allow side effects.
* The return type of `reducerAction` must match the type of `initialState`. If TypeScript infers a mismatch, you may need to explicitly annotate your state type.
* If you set state after `await` in the `reducerAction` you currently need to wrap the state update in an additional `startTransition`. See the [startTransition](/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition) docs for more info.
* If you call `reducerAction` outside of a Transition (for example, directly in an event handler), wrap it in [`startTransition`](/reference/react/startTransition). See [Troubleshooting](/reference/react/useActionState#async-function-outside-transition) for more info.
* When using Server Functions, `actionPayload` needs to be [serializable](/reference/rsc/use-server#serializable-parameters-and-return-values) (values like plain objects, arrays, strings, and numbers).

<DeepDive>
Expand Down
28 changes: 19 additions & 9 deletions src/content/reference/react/useTransition.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function SubmitButton({ submitAction }) {

#### Parameters {/*starttransition-parameters*/}

* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). React calls `action` immediately with no parameters and marks all state updates scheduled synchronously during the `action` function call as Transitions. Any async calls that are awaited in the `action` will be included in the Transition, but currently require wrapping any `set` functions after the `await` in an additional `startTransition` (see [Troubleshooting](#react-doesnt-treat-my-state-update-after-await-as-a-transition)). State updates marked as Transitions will be [non-blocking](#perform-non-blocking-updates-with-actions) and [will not display unwanted loading indicators](#preventing-unwanted-loading-indicators).
* `action`: A function that updates some state by calling one or more [`set` functions](/reference/react/useState#setstate). The function can be synchronous or asynchronous. React calls `action` immediately with no parameters and marks all state updates scheduled during the `action` as Transitions, including updates after `await`. State updates marked as Transitions will be [non-blocking](#perform-non-blocking-updates-with-actions) and [will not display unwanted loading indicators](#preventing-unwanted-loading-indicators).

#### Returns {/*starttransition-returns*/}

Expand All @@ -109,8 +109,6 @@ function SubmitButton({ submitAction }) {

* The function you pass to `startTransition` is called immediately, marking all state updates that happen while it executes as Transitions. If you try to perform state updates in a `setTimeout`, for example, they won't be marked as Transitions.

* You must wrap any state updates after any async requests in another `startTransition` to mark them as Transitions. This is a known limitation that we will fix in the future (see [Troubleshooting](#react-doesnt-treat-my-state-update-after-await-as-a-transition)).

* The `startTransition` function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect)

* A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input update.
Expand Down Expand Up @@ -1676,7 +1674,7 @@ startTransition(() => {
});
```

The function you pass to `startTransition` must be synchronous. You can't mark an update as a Transition like this:
The function you pass to `startTransition` is called immediately, but updates must be scheduled *during* that call. You can't mark an update as a Transition if you defer it with `setTimeout`:

```js
startTransition(() => {
Expand All @@ -1702,17 +1700,31 @@ setTimeout(() => {

### React doesn't treat my state update after `await` as a Transition {/*react-doesnt-treat-my-state-update-after-await-as-a-transition*/}

When you use `await` inside a `startTransition` function, the state updates that happen after the `await` are not marked as Transitions. You must wrap state updates after each `await` in a `startTransition` call:
In React 19, the `startTransition` function returned by `useTransition` supports async Actions. State updates after `await` are automatically included in the Transition:

```js
const [isPending, startTransition] = useTransition();

startTransition(async () => {
await someAsyncFunction();
// ✅ Updates after await are part of the Transition
setPage('/about');
});
```

This limitation only applies to the standalone [`startTransition`](/reference/react/startTransition) function. When you use it outside a component, state updates after `await` are not automatically marked as Transitions. Wrap them in another `startTransition` call:

```js
import { startTransition } from 'react';

startTransition(async () => {
await someAsyncFunction();
// ❌ Not using startTransition after await
// ❌ Not marked as a Transition with standalone startTransition
setPage('/about');
});
```

However, this works instead:
This works instead:

```js
startTransition(async () => {
Expand All @@ -1724,8 +1736,6 @@ startTransition(async () => {
});
```

This is a JavaScript limitation due to React losing the scope of the async context. In the future, when [AsyncContext](https://github.com/tc39/proposal-async-context) is available, this limitation will be removed.

---

### I want to call `useTransition` from outside a component {/*i-want-to-call-usetransition-from-outside-a-component*/}
Expand Down
Loading