Â
React JS 19 is coming soon with exciting updates ✨
React is evolving and some exciting updates are coming up by the end of 2024. These updates are aimed at making it easier for developers to use this powerful library. Let's explore what's in store! âš¡
Let's see what we've got in store, shall we?
-
Say goodbye to some Hooks and HOCs!
With the new React Compiler, you won't need to worry about using
useMemo
,useCallback
, ormemo
anymore. This new feature will do all the hard work for you! It's pretty smart too, as it will optimize your components by caching computations and memoizing callbacks without you having to do anything manually. -
Simplified Refs:
Passing
ref
will become as easy as passing a prop. TheforwardRef
API will be set aside, reducing boilerplate and making component APIs more predictable and easier to understand. -
New Patterns Over
React.lazy
: Server Components (RSC) and new patterns like promise-as-a-child will replaceReact.lazy
for code splitting and component loading, offering more efficient ways to dynamically load components based on user interactions and network conditions. -
Context and Suspense Changes:
The
useContext
hook transforms intouse(Context)
, embedding context consumption directly into theuse
hook for a more unified hooks API. Additionally, throwing promises in components for Suspense will be replaced withuse(promise)
, standardizing asynchronous data fetching with the rest of the hooks ecosystem. -
Streamlined Context Providers:
Creating context will be more straightforward without the
.Provider
component. You'll be able to use
directly, which simplifies context creation and provides a more elegant syntax.
Andrew Clark @reactjs core team, @nextjs, @vercel
Overview of React 19's New Features
React Compiler: A Game Changer
The new React compiler is a standout feature. It automates re-rendering processes, allowing developers to focus more on crafting unique user experiences rather than optimizing performance manually. This innovation is already in action at Instagram, setting a precedent for its effectiveness in real-world applications.
// Before React 19
import React, { useState, useCallback } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []);
return <button onClick={increment}>Count: {count}</button>;
}
// With React 19 Compiler
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => setCount(c => c + 1);
return <button onClick={increment}>Count: {count}</button>;
}
💡 The manual optimization using useCallback is no longer necessary.
Server Components
React 19 now allows server components to be integrated directly which can lead to SEO improvements and better performance by rendering components on the server-side. This integration is especially powerful when combined with frameworks like Next.js, offering a seamless experience from server to client
// This React 19 feature enables components to run on the server, enhancing performance and SEO.
'use server';
export default async function getUsername(userId) {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data.username;
}
Server Actions
The introduction of Actions transforms how forms interact within React applications. By binding Actions directly to form elements, React 19 allows for server-side executions, thereby enhancing the responsiveness and interactivity of web applications.
async function handleLogin(formData: FormData): Promise<void> {
'use server';
const username = formData.get('username');
const password = formData.get('password');
console.log(username, password)
// this is where you would send the data to the server, it would be part of the server action folder/file
}
export default async function LoginForm() {
return (
<form action={handleLogin}>
<input name="username" type="text" placeholder="Username" />
<input name="password" type="password" placeholder="Password" />
<button type="submit">Log In</button>
</form>
);
}
Async Transitions
React 19 introduces a new pattern for handling data mutations and state updates, which is especially beneficial when handling form submissions or any sequence that involves a user interaction that updates data. The new useTransition
hook and action framework simplify the handling of asynchronous updates, enabling cleaner and more efficient state management.
// Example using useTransition for better state management in React 19
function UpdateName({}) {
const [name, setName] = useState("");
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();
const handleSubmit = async () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect("/path");
});
};
return (
<div>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button onClick={handleSubmit} disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</div>
);
}
The async transition will instantly set theisPending
state to true, execute the async request(s), and changeisPending
to false after all transitions. This ensures the UI remains responsive and interactive during data updates.
Simplifying Form Handling with Form Actions
React 19 further simplifies form handling by permitting direct passing of functions to the action
and formAction
props.
// Example using <form> Actions in React 19
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
redirect("/path");
}
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
So, React 19 is bringing in some cool stuff. It's got this new thing called useOptmistic that helps manage optimistic updates. They've also introduced a new hook called useActionState which is pretty handy for Actions. Over in react-dom, they've added Form Actions that automatically manage forms, and useFormStatus for the common cases with Actions in forms.
NEW HOOKS 💡 ⚡
-
useActionState
: Simplifies the management of action states in applications, especially when dealing with forms. -
useFormStatus
: Provides easy access to the status of forms, helping manage UI changes based on form state. -
useOptimistic
: Allows developers to implement optimistic UI updates, showing changes instantaneously while the data mutation is processed in the background.
Example using useActionState:
const [error, submitAction, isPending] = useActionState(async (previousState, newName) => {
const error = await updateName(newName);
if (error) {
// You can return any result of the action.
// Here, we return only the error.
return error;
}
// handle success
});
Example using useFormStatus:
import {useFormStatus} from 'react-dom';
function DesignButton() {
const {pending} = useFormStatus();
return <button type="submit" disabled={pending} />
}
Example using useOptmistic:
function ChangeName({ currentName, onUpdateName }) {
const [optimisticName, setOptimisticName] = useOptimistic(currentName);
const submitAction = async formData => {
const newName = formData.get("name");
setOptimisticName(newName); // Optimistically update UI
const updatedName = await updateName(newName);
onUpdateName(updatedName); // Update with actual response
};
return (
<form action={submitAction}>
<p>Your name is: {optimisticName}</p>
<input type="text" name="name" />
</form>
);
}
And here's the biggie we've all been waiting for: New API: use
💜
In React 19, a new API is introduced for reading resources during rendering:use
. For example, you can utilizeuse
to read a promise. React will suspend until the promise is resolved.
import {use} from 'react';
function Comments({commentsPromise}) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map(comment => <p key={comment.id}>{comment}</p>);
}
function Page({commentsPromise}) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
)
}
Awesome! But let's see this in action, shall we? Check out the example I'm dropping below comparing useEffect
and use
.
Here’s an example using the traditional useEffect
hook to fetch data:
import { useEffect, useState } from "react";
const JokeItem = ({ joke }) => {
return (
<div className="bg-blue-50 shadow-md p-4 my-6 rounded-lg">
<h2 className="text-xl font-bold">{joke.value}</h2>
</div>
);
};
const Joke = () => {
const [joke, setJoke] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchJoke = async () => {
try {
const res = await fetch("https://api.chucknorris.io/jokes/random");
const data = await res.json();
setJoke(data);
setLoading(false);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
};
fetchJoke();
}, []);
if (loading) {
return <h2 className="text-2xl text-center font-bold mt-5">Loading...</h2>;
}
return <JokeItem joke={joke} />;
};
export default Joke;
In the version we got here,useEffect
is like the stage manager, handling all the setup and teardown for fetching our data. And we're taking care ofloading
andjoke
state ourselves, old school style.
Now, let’s see how the new use
function simplifies the same operation:
import { use, Suspense } from "react";
const fetchData = async () => {
const res = await fetch("https://api.chucknorris.io/jokes/random");
return res.json();
};
const JokeItem = () => {
const joke = use(fetchData());
return (
<div className="bg-blue-50 shadow-md p-4 my-6 rounded-lg">
<h2 className="text-xl font-bold">{joke.value}</h2>
</div>
);
};
const Joke = () => {
return (
<Suspense
fallback={
<h2 className="text-2xl text-center font-bold mt-5">Loading...</h2>
}
>
<JokeItem />
</Suspense>
);
};
export { Joke as UseExample1 };
So, what happens here is,use
directly handles the promise returned byfetchData
, suspending the component’s rendering until the data is available. React’sSuspense
component then takes care of displaying a fallback UI during the loading state. The cool thing is, this way gets rid of the boring repetitive stuff, no need to manually manage any loading state and simplifying error handling.
Key Takeaways
-
Simplicity: The
use
API allows developers to write less code and manage fewer states manually, focusing more on the core functionality of components. -
Declarative: With
use
, components declare what data they need, not how or when to fetch it, aligning with React’s overall declarative approach. -
Efficiency: Suspense integrates seamlessly with
use
, improving handling of asynchronous data fetching by optimizing rendering and reducing the impact on the UI responsiveness.
Hope it was help full, and lets keep learning That's just a sneak peek of all the awesome features on the horizon! If you're keen to stay in the loop, make sure to check out the React Blog regularly, or better yet, keep an eye on my blog for the latest updates and insights. Hope you found this helpful—let's keep the learning journey going! 💜 ⚡
Summary
React 19 is poised to significantly enhance the efficiency, performance, and simplicity of developing React applications. From its new compiler to improved hooks and server-side components, React 19 encourages a more streamlined, performance-oriented approach to building modern web applications.