New use & useOptimistic hooks in React package
Mon Feb 26 2024
React has added two new hooks — use
and useOptimistic
— now available in the stable React package.
These hooks make handling server-client interactions and managing async UI updates much simpler and more natural.
use hook
The use
hook lets you read the value of a resource such as a Promise or Context directly inside your component.
Unlike other hooks, use
can be called inside loops, conditionals, or any block — while still following React’s rules of hooks (it must be used inside a component or another hook).
const value = use(resource);
Usage
Reading context values
use
works similarly to useContext
, but it’s more flexible.
It can be used inside conditionals or loops, which useContext
doesn’t allow. React recommends using use
over useContext
since it’s more adaptable.
"use client";
import ThemeContext from "@/contexts";
import Button from "@/components";
export default function GetStartedButton({ newUI, children }) {
if (newUI) {
const theme = use(ThemeContext); // using hook inside condition
return <Button theme={theme}>{children}</Button>;
}
return <button>{children}</button>;
}
Streaming data from server to client
A Promise can be passed from a Server Component to a Client Component and resolved in the Client Component using the use
hook.
If you use await
in a Server Component, rendering is blocked until the promise resolves:
export default async function Home() {
const feeds = await getFeed();
const trends = await getTrends();
return (
<div>
<Feed data={feeds} />
<Explore data={trends} />
</div>
);
}
To avoid blocking, you can pass the promise directly to the Client Component.
React will render parts of the page in parallel and suspend where needed using Suspense
.
export default async function Home() {
const feedsPromise = getFeed();
const trendsPromise = getTrends();
return (
<div>
<Suspense fallback="Loading feed...">
<Feed data={feedsPromise} />
</Suspense>
<Suspense fallback="Loading trends...">
<Explore data={trendsPromise} />
</Suspense>
</div>
);
}
In the Client Component, you can resolve the promise directly with use
:
export default function Feed({ data }) {
const resolvedData = use(data);
return <div>{/* render feed here */}</div>;
}
The use
hook integrates automatically with Suspense and Error Boundaries.
When the promise is pending, the fallback is shown, and if it fails, the nearest Error Boundary handles the error.
Note:
Make sure the promise result is JSON serializable when passing data from the server to the client.
useOptimistic hook
useOptimistic
is another new React hook that helps you optimistically update the UI.
When performing async actions, instead of waiting for the server response, you can show an immediate UI update and replace it later when the real data arrives.
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
Usage
Optimistically updating forms
export default function MessagesContainer({ messages, send }) {
const [optimisticMessages, addMessage] = useOptimistic(
messages,
(state, newMessage) => [...state, newMessage]
);
const [inputMessage, setInputMessage] = useState("");
async function handleSend() {
const message = inputMessage;
setInputMessage("");
addMessage({
body: message,
pending: true,
key: uuid(),
});
await send(message);
}
return (
<div>
{optimisticMessages.map((message) => (
<Message key={message.key} {...message} />
))}
<div>
<input
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
/>
<button onClick={handleSend}>Send</button>
</div>
</div>
);
}
function Message({ body, pending }) {
return <p>{body} {pending && " - sending..."}</p>;
}
When you send a message, it appears instantly with the “sending...” suffix before the server responds. Once the actual data is returned and revalidated, the pending state is removed. This makes interactions feel faster and smoother for users.
Both use
and useOptimistic
are now part of stable React.
They make data handling and UI updates more seamless — bringing a smoother bridge between server logic and the client experience.