Understanding the New “use” Hook in React 19 and Its Impact on UI Development
This article introduces React 19’s new use hook that reduces reliance on useEffect, explains how to work with resolved promises, demonstrates conditional usage and integration with Suspense through detailed code examples, and discusses practical considerations when using the hook in modern frontend projects.
Disclaimer: the following conclusions are the author’s personal opinions and should be taken lightly.
While working on a project that required the shadcn UI library, the author discovered that React 19 had been released and decided to explore its new features.
useEffect is a powerful but often misused hook; many developers struggle with its dependency array and can cause project instability, especially when dealing with closures.
React 19 introduces a new hook called use that aims to handle asynchronous development without the need for useEffect, fundamentally changing how UI interactions are built.
React 19 will dramatically change our UI interaction patterns
use
The use hook is the most important addition in React 19 for improving asynchronous development experience, and it significantly reduces the importance of useEffect.
It can read values from a Promise or from a context resource.
Correctly Understanding Promise
const value = use(promise);Note that the Promise must already be created and resolved; use reads the resolved value.
Promise with Existing State
import React from 'react';
import { use } from 'react';
import { resolve } from 'styled-jsx/css';
const page = () => {
const api2 = new Promise((resolve) => {
resolve({ value: 2 });
});
const result = use(api2);
return (
{result.value}
);
};
export default page;Promise Created at Function Execution
function _api3() {
return new Promise((resolve) => {
resolve('api3');
});
}
const result3 = use(_api3());
console.log(result3);Because the function returns a Promise immediately, use cannot read its value on the first render and will throw an error.
async/await is not yet supported in Client Components, only Server Components. This error is often caused by accidentally adding 'use client' to a module that was originally written for the server.
Note: if you are using Next.js the code runs fine; the author is using Vite.
Using use in Conditional Statements
Like other hooks, use must be called inside a function component, but it can be used inside loops and conditional statements.
The following example demonstrates calling use inside an if (!loading) block.
import { use } from 'react';
import { useState } from 'react';
import Message from './Message';
import Button from './Button';
import Skeleton from './Skeleton';
const _api2 = new Promise((resolve) => {
resolve({ value: 'Unlike React Hooks, use can be called within loops and conditional statements like if. Like React Hooks, the function that calls use must be a Component or Hook.' });
});
const page = () => {
const [loading, setLoading] = useState(false);
let result = { value: '' };
if (!loading) {
result = use(_api2);
}
return (
<>
{loading ?
:
}
setLoading(!loading)}>切换
);
};
export default page;Suspense
Directly using use on a Promise that has not yet resolved throws an exception.
function _api3() {
return new Promise((resolve) => {
resolve({ value: '_api3' });
});
}
// bad: get an error
const result = use(_api3());In most real‑world scenarios the Promise is not immediately resolved, so we need a way to handle the pending state.
React 19 allows us to combine use with Suspense to catch the error and render a fallback.
import { Suspense, use } from 'react';
import Message from './Message';
function _api3() {
return new Promise((resolve) => {
resolve({ value: 'React does not preserve any state for renders that got suspended before they were able to mount for the first time. When the component has loaded, React will retry rendering the suspended tree from scratch.' });
});
}
export default function Demo01() {
const promise = _api3();
return (
);
}
function Content(props) {
const { value } = use(props.promise);
return
;
}By defining a small Content component that consumes the Promise, Suspense can catch the thrown error and display a fallback (e.g., a skeleton screen) until the data resolves.
Although use reduces the need for useEffect , many projects will still rely on useEffect for side‑effects; developers can continue using the hook they are comfortable with.
Click to follow the public account “Technical Dry Goods – Timely Delivery!”
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.