React|Built-in Hook Mastery

use API: The Evolution of useContext and Handling Promises (Suspense)

9
use API: The Evolution of useContext and Handling Promises (Suspense)

Chris is building a complex dashboard component.

This component renders differently based on user settings: 'Normal Mode' and 'Advanced Mode'. He wants to access a specific Context (AdvancedContext) to fetch data only when in Advanced Mode.

So, Chris wrote the code intuitively.

typescript
// ❌ Chris's Mistake: Hooks cannot be used inside conditional statements.
function Dashboard({ isAdvanced }) {
  if (isAdvanced) {
    // Error: React Hooks must be called in the exact same order...
    const advancedData = useContext(AdvancedContext);
    return <AdvancedView data={advancedData} />;
  }
  
  return <SimpleView />;
}

The moment he pressed save, React spewed a red error: "Hook rule violation."

React Hooks are not magic; they are an order-based system relying on array indices. Therefore, they cannot be called inside loops, conditions, or nested functions.

Eventually, Chris had to pull useContext up to the top level, even though the data wasn't needed when isAdvanced was false.

However, in React 19, this restriction is lifted. Thanks to the arrival of the new use API, which behaves like a hook but isn't one.

1. Consuming Context Flexibly

The use API looks similar to React Hooks, but there is a decisive difference: It can be called inside conditional statements and loops.

Now Chris doesn't have to forcefully hoist the hook. He can simply "read" the Context when and where it is needed.

typescript
// ✅ React 19: Using the use API
import { use } from 'react';

function Dashboard({ isAdvanced }) {
  if (isAdvanced) {
    // Reading Context inside a conditional statement is allowed!
    const advancedData = use(AdvancedContext);
    return <AdvancedView data={advancedData} />;
  }
  
  return <SimpleView />;
}

use can completely replace useContext. Now, without interrupting the flow of component logic, you can fetch Context values naturally following the data flow. This increases the code's Cohesion.

2. Unwrapping Promises: Async like Sync

The true value of the use API shines when handling Promises (Async tasks).

Until now, to fetch asynchronous data, we had to combine useEffect and useState or rely on libraries like TanStack Query. It required a complex process of managing isLoading state while fetching and rendering once the data arrived.

However, the use API can accept a Promise object directly as an argument. And it Suspends React rendering until that Promise is Resolved.

Using Promises in Client Components

Imagine fetching data in a Server Component (RSC) and passing that Promise to a Client Component (Message).

typescript
// ClientComponent.tsx
import { use, Suspense } from 'react';

function Message({ messagePromise }: { messagePromise: Promise<string> }) {
  // 1. Waits until the Promise is resolved. (Pauses here)
  // 2. Returns the result (string) once resolved.
  const messageContent = use(messagePromise);

  return <p>{messageContent}</p>;
}

export function MessageContainer({ promise }) {
  return (
    // 3. The parent Suspense handles the UI to show while waiting.
    <Suspense fallback={<p>Downloading message...</p>}>
      <Message messagePromise={promise} />
    </Suspense>
  );
}

Looking at this code, the await keyword is nowhere to be seen. Yet, asynchronous data is stored in messageContent just like a synchronous variable.

This is the "Suspense-based Data Fetching" that React pursues.

3. Principle: A New Mental Model for 'Reading' Values

The use API is not a function for "Fetching" data, but for "Reading" data.

  • The component renders and encounters use(promise).
  • If the Promise is still Pending, React thinks, "Not ready yet?" and stops rendering (Throw Promise), showing the nearest Suspense fallback.
  • When the Promise is Resolved, React re-executes the component.
  • This time, use(promise) returns the result value immediately. Rendering completes.
  • What if it's Rejected (Error)? The nearest Error Boundary catches it.
  • This pattern is similar to useSuspenseQuery we learned in Part 2. But now, you can write "Declarative code without loading states" using only React's native features without external libraries.

    4. Cautions and Limitations

    The use API is not a silver bullet. There are a few rules to follow.

    1. Usable Only During Rendering

    use must only be called during the render phase of a component or hook. It cannot be used inside event handlers (onClick) or useEffect. (Just use await there.)

    2. Server Components vs. Client Components

  • Server Components: You can use async/await directly, so use isn't strictly necessary.
  • Client Components: You shouldn't use async/await (as they cease to be hooks). This is where use shines when processing Promises passed as props.
  • 3. Caching is Separate

    use is merely a tool for reading data; it does not cache data or prevent duplicate requests. To cache API requests, you still need to use TanStack Query or your framework's (Next.js) caching features.

    Key Takeaways

  • use API: A new feature in React 19 that allows reading Context and Promises.
  • Conditionally Callable: Unlike existing hooks (useContext), it can be freely used inside if statements or loops, maximizing flexibility.
  • Promise Handling: When used as use(promise), it Suspends component rendering until the async data is ready.
  • Paradigm Shift: We must shift our thinking from "Request and Wait" to "Read when Ready." Delegate loading handling to Suspense and error handling to Error Boundary.

  • Context and async handling have become this elegant. Then how has the biggest headache, "Form Handling," changed?

    It's time to be liberated from the grunt work of manually creating isSubmitting, error, and result states with useState.

    Continuing in: "useActionState & useFormStatus: The Revolution of Form Management."

    🔗 References

  • React Docs - use API
  • React 19 Hooks Changes
  • RFC: First-class Support for Promises
  • Comments (0)

    0/1000 characters
    Loading comments...