This content originally appeared on Level Up Coding - Medium and was authored by Imran Farooq
The React 19 Release Candidate (RC) was released on April 25, 2024. This version introduces a variety of new features that are poised to transform React development. Contrary to popular belief, the React team’s focus extends beyond just React Server Components and Next.js.
The upcoming release emphasizes web primitives, with form data being one of the key primitives. This shift aims to enhance the core capabilities of React, making it more versatile and efficient for developers.
Let’s look at a straightforward example. We’re utilizing the useState hook to handle three states: isLoading, data, and message. While it functions correctly, there’s a significant amount of repetitive code to manage these states:
export default function Profile() {
const [name, setName] = useState('');
const [message, setMessage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const submitAction = async () => {
setIsLoading(true);
const data = await changeName(name);
setIsLoading(false);
setMessage(data.message);
};
return (
<form action={submitAction}>
<input value={name} onChange={(event) => setName(event.target.value)} />
<button type="submit" disabled={isLoading}>
{isLoading? "Updating" : "Update"}
</button>
<p>{message}</p>
</form>
);
}
In React 19, you can now use async functions in transitions to automatically manage pending states, errors, forms, and optimistic updates.
In React 19, functions that initiate transitions are now known as actions. An action can trigger a transition in various ways. You can create an action using the useActionState hook, which simplifies creating actions and provides status updates on the transition. This hook then sets the state based on the returned data.
The new client-side hooks in React 19 address major issues with data mutations and form management. They simplify handling pending states, errors, optimistic updates, and sequential requests, which previously required manual intervention.
Let’s look into these new hooks in detail.
1. useActionState hook
useActionState is a hook that provides a more streamlined way to handle form actions.
useActionState accepts 3 argument
- fn: The function to be called when the form is submitted or the button pressed.
- initialState: Initial state
- permalink (optional): A string containing the unique page URL that this form modifies.
It returns:
- The initial state or the data returned when the action is completed.
- The action function.
- A pending state indicator.
import changeName from "./action"
export default function Profile() {
const [state, formAction, isPending] = useActionState(changeName,null
);
return (
<form action={formAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>
{isPending ? "Updating" : "Update"}
</button>
<p>{data?.message}</p>
</form>
);
}
// action.js
export async function changeName(prevState,formData) {
const name = formData.get("name")
if (name) {
return { success: true, message: "Name updated" };
} else {
return { success: false, message: "Name cannot be blank" };
}
}
With useActionState, there’s no need for a separate data state because the hook returns it. The submit action provided to the hook automatically receives the current state and form data as arguments.
This means we don’t have to manually set the user’s input state; instead, we can directly retrieve it from the form data. Additionally, the hook provides an isPending state, ensuring consistent behavior with less boilerplate code.
2. useFormStatus hook
Building design systems often involves creating components that rely on data from the surrounding <form>. Traditionally, this data is passed down through props, which can lead to extensive prop drilling or the use of Context.
To simplify this common scenario, React 19 introduces the new useFormStatus hook. This hook provides an easy way to track the status of form submissions.
It does not take any parameters and returns a status object with the following properties:
1. `pending`: Status of the form submission.
2. `data`: Form data.
3. `method`: HTTP method used for submission (e.g., “POST”).
4. `action`: A reference to the function passed to the action prop on the parent `<form>`.
Things to note:
1. The useFormStatus hook must be called from a component that is rendered inside a `<form>`.
2. It will not return status information for any `<form>` rendered in that same component or its child components.
In this example, useFormStatus is called in a child component of the form, making the form status and data available through the hook.
export default function App() {
const ref = useRef(null);
return (
<form ref={ref} action={async (formData) => {
await submitForm(formData);
ref.current.reset();
}}>
<UsernameForm />
</form>
);
}
export default function ProfileName() {
const {pending, data} = useFormStatus();
return (
<div>
<h3>Request a Pofile Name: </h3>
<input type="text" name="profilenName" disabled={pending}/>
<button type="submit" disabled={pending}>Submit</button>
<br />
<p>{data ? `Requesting ${data?.get("profileName")}...`: ''}</p>
</div>
);
}
When the useFormStatus hook is called inside the same component as the form, pending is never tracked and will always be false.
3. useOptimistic hook
The useOptimistic hook lets us create a smoother user experience for forms. It allows us to update the interface with the expected outcome immediately after submission, even before the server confirms the change. This eliminates the wait for the server’s response, making the app feel more responsive.
Here’s how it works:
const [optimisticState, addOptimistic] = useOptimistic(state, updateFn);
We supply the current state along with an update function (updateFn) that combines this state with an optimistic update. When an action begins, addOptimistic is called with the optimistic value. React then invokes updateFn and renders the optimistic state.
If the action is successful, the optimistic state turns into the final state. If it fails, React swiftly reverts to the original state, ensuring the UI remains responsive and free from incorrect data.
"use client";
import { useActionState, useOptimistic } from "react";
import { saveItem } from "./actions";
const TodoList = ({ items }) => {
const [optItem, addOptItem] = useOptimistic(items, (state, newItem) => [
...state,
{
name: newItem,
sending: true,
},
]);
const formAction = async (formData) => {
addOptItem(formData.get("item"));
await saveItem(formData);
};
return (
<>
<h2>My list</h2>
<form action={formAction}>
<input type="text" name="item" />
<button type="submit">{pending ? "Adding..." : "Add"}</button>
</form>
<ul>
{optItem?.map((item, index) => (
<li key={index}>{item.name}</li>
))}
</ul>
</>
);
};
export default TodoList;
4. use hook
The use hook streamlines data fetching and handling promises.
i. Reading promise with use
It enables us to directly use the result of a promise within our component, eliminating unnecessary boilerplate code.
const products= use(fetchProducts());
The use hook accepts a promise and returns its result. It also integrates seamlessly with Suspense and error boundaries.
When we use the use hook, our component pauses until the provided promise completes. If our component is wrapped in a Suspense component, a fallback UI will appear while waiting.
Once the promise successfully resolves, the fallback disappears, and the data is rendered. However, if the promise is rejected, the nearest Error Boundary’s fallback will be displayed instead.
NOTE: Unlike React Hooks, use can be called within loops and conditional statements.
ii. Reading context with use
When a context is passed to use, it functions similarly to useContext. However, unlike useContext, which must be called at the top level of our component, use can be called within conditionals like if statements and loops like for loops. This flexibility makes use a preferred choice over useContext.
export default function App() {
return (
<ThemeContext.Provider value="dark">
<Sidebar />
</ThemeContext.Provider>
)
}
function Sidebar({ children }) {
const theme = use(ThemeContext); //dark
const className = 'sidebar-' + theme;
return (
<section className={className}>
<h1>Sidebar</h1>
{children}
</section>
)
}
Conclusion
React 19 supercharges functional components with awesome new hooks!
These hooks make common tasks easier, speeding up development and making it more fun.
1. **Better User Experience**: The useOptimistic hook lets us update the UI right away when a user interacts with a form, even before the server confirms the data. This gives instant feedback and keeps users engaged.
2. **Easy Form Handling**: The useFormStatus and useActionState hooks make managing forms simpler. They track submission status and centralize form state, cutting down on extra code.
3. **Simple Data Fetching**: The use hook works with promises and Suspense, letting us fetch data in a clean and concise way, reducing the need for additional code.
Overall, these new hooks benefit developers by:
- Saving Time: They simplify common tasks, cutting down development time.
- Promoting Code Reusability: Centralized state management encourages reusing code.
- Building Better UIs: Faster development and a focus on user experience result in more engaging and high-performing applications.
Tip Me
Imran Farooq is Creating Content On React.js and Next.js
Game Changing New Hooks of React 19 was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Imran Farooq
Imran Farooq | Sciencx (2024-09-12T15:11:30+00:00) Game Changing New Hooks of React 19. Retrieved from https://www.scien.cx/2024/09/12/game-changing-new-hooks-of-react-19/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.