Concurrent Mode API Reference (Experimental)

.scary > blockquote { background-color: rgba(237, 51, 21, 0.2); border-left-color: #ed3315; }

Caution:

This page was about experimental features that aren't yet available in a stable release. It was aimed at early adopters and people who are curious.

Much of the information on this page is now outdated and exists only for archival purposes. Please refer to the React 18 Alpha announcement post for the up-to-date information.

Before React 18 is released, we will replace this page with stable documentation.

This page is an API reference for the React Concurrent Mode. If you're looking for a guided introduction instead, check out Concurrent UI Patterns.

Note: This is a Community Preview and not the final stable version. There will likely be future changes to these APIs. Use at your own risk!

  • Enabling Concurrent Mode

    • createRoot

  • Suspense

    • Suspense

    • SuspenseList

    • useTransition

    • useDeferredValue

Enabling Concurrent Mode

createRoot

ReactDOM.createRoot(rootNode).render(<App />);

Replaces ReactDOM.render(<App />, rootNode) and enables Concurrent Mode.

For more information on Concurrent Mode, check out the Concurrent Mode documentation.

Suspense API

Suspense

<Suspense fallback={<h1>Loading...</h1>}>
  <ProfilePhoto />
  <ProfileDetails />
</Suspense>

Suspense lets your components "wait" for something before they can render, showing a fallback while waiting.

In this example, ProfileDetails is waiting for an asynchronous API call to fetch some data. While we wait for ProfileDetails and ProfilePhoto, we will show the Loading... fallback instead. It is important to note that until all children inside <Suspense> have loaded, we will continue to show the fallback.

Suspense takes two props:

  • fallback takes a loading indicator. The fallback is shown until all of the children of the Suspense component have finished rendering.

  • unstable_avoidThisFallback takes a boolean. It tells React whether to "skip" revealing this boundary during the initial load. This API will likely be removed in a future release.

<SuspenseList>

<SuspenseList revealOrder="forwards">
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={1} />
  </Suspense>
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={2} />
  </Suspense>
  <Suspense fallback={'Loading...'}>
    <ProfilePicture id={3} />
  </Suspense>
  ...
</SuspenseList>

SuspenseList helps coordinate many components that can suspend by orchestrating the order in which these components are revealed to the user.

When multiple components need to fetch data, this data may arrive in an unpredictable order. However, if you wrap these items in a SuspenseList, React will not show an item in the list until previous items have been displayed (this behavior is adjustable).

SuspenseList takes two props:

  • revealOrder (forwards, backwards, together) defines the order in which the SuspenseList children should be revealed.

    • together reveals all of them when they're ready instead of one by one.

  • tail (collapsed, hidden) dictates how unloaded items in a SuspenseList is shown.

    • By default, SuspenseList will show all fallbacks in the list.

    • collapsed shows only the next fallback in the list.

    • hidden doesn't show any unloaded items.

Note that SuspenseList only operates on the closest Suspense and SuspenseList components below it. It does not search for boundaries deeper than one level. However, it is possible to nest multiple SuspenseList components in each other to build grids.

useTransition

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);

useTransition allows components to avoid undesirable loading states by waiting for content to load before transitioning to the next screen. It also allows components to defer slower, data fetching updates until subsequent renders so that more crucial updates can be rendered immediately.

The useTransition hook returns two values in an array.

  • startTransition is a function that takes a callback. We can use it to tell React which state we want to defer.

  • isPending is a boolean. It's React's way of informing us whether we're waiting for the transition to finish.

If some state update causes a component to suspend, that state update should be wrapped in a transition.

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

function App() {
  const [resource, setResource] = useState(initialResource);
  const [startTransition, isPending] = useTransition(SUSPENSE_CONFIG);
  return (
    <>
      <button
        disabled={isPending}
        onClick={() => {
          startTransition(() => {
            const nextUserId = getNextId(resource.userId);
            setResource(fetchProfileData(nextUserId));
          });
        }}
      >
        Next
      </button>
      {isPending ? " Loading..." : null}
      <Suspense fallback={<Spinner />}>
        <ProfilePage resource={resource} />
      </Suspense>
    </>
  );
}

In this code, we've wrapped our data fetching with startTransition. This allows us to start fetching the profile data right away, while deferring the render of the next profile page and its associated Spinner for 2 seconds (the time shown in timeoutMs).

The isPending boolean lets React know that our component is transitioning, so we are able to let the user know this by showing some loading text on the previous profile page.

For an in-depth look at transitions, you can read Concurrent UI Patterns.

useTransition Config

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

useTransition accepts an optional Suspense Config with a timeoutMs. This timeout (in milliseconds) tells React how long to wait before showing the next state (the new Profile Page in the above example).

Note: We recommend that you share Suspense Config between different modules.

useDeferredValue

const deferredValue = useDeferredValue(value, { timeoutMs: 2000 });

Returns a deferred version of the value that may "lag behind" it for at most timeoutMs.

This is commonly used to keep the interface responsive when you have something that renders immediately based on user input and something that needs to wait for a data fetch.

A good example of this is a text input.

function App() {
  const [text, setText] = useState("hello");
  const deferredText = useDeferredValue(text, { timeoutMs: 2000 }); 

  return (
    <div className="App">
      {/* Keep passing the current text to the input */}
      <input value={text} onChange={handleChange} />
      ...
      {/* But the list is allowed to "lag behind" when necessary */}
      <MySlowList text={deferredText} />
    </div>
  );
 }

This allows us to start showing the new text for the input immediately, which allows the webpage to feel responsive. Meanwhile, MySlowList "lags behind" for up to 2 seconds according to the timeoutMs before updating, allowing it to render with the current text in the background.

For an in-depth look at deferring values, you can read Concurrent UI Patterns.

useDeferredValue Config

const SUSPENSE_CONFIG = { timeoutMs: 2000 };

useDeferredValue accepts an optional Suspense Config with a timeoutMs. This timeout (in milliseconds) tells React how long the deferred value is allowed to lag behind.

React will always try to use a shorter lag when network and device allows it.

Last updated