DEV Community

Cover image for Actions - React 19
Anto Vinish
Anto Vinish

Posted on • Updated on

Actions - React 19

Actions and Form Utilities in React

React has been a dominant force in the frontend development world for the past decade, thanks to its simplicity and powerful features. Despite its widespread use, one area where React has often been criticized is form handling. Although forms are a crucial part of web development, React hasn't always provided the most straightforward solutions for managing them.

With the advent of React 19, new features and hooks have been introduced, promising to simplify and enhance form handling. Let's dive into these new capabilities and see what they offer.

Classic Form in React

Here's an example of a traditional form in React:

    <form action="/some_post_url">
        <div>
          Name: <input name="name" type="text" placeholder="Name" />
        </div>
        <div>
          Age: <input name="age" type="text" placeholder="Age" />
        </div>
        <div>
          <button type="submit">
            Add User
          </button>
        </div>
    </form>
Enter fullscreen mode Exit fullscreen mode

This form sends data to /some_post_url upon submission. Now, let's explore how new React features can enhance this process.

Using Actions

export default function AddUser() {

  const submitHandler = async (previousState, formData) => {
    try {
      const body = {
        name: formData.get("name"),
        age: formData.get("age"),
      };
      const response = await fetch("http://localhost:3003/users", {
        method: "POST",
        body: JSON.stringify(body),
        headers: {
          "Content-Type": "application/json",
        },
      });
      // return proper response
      return response.json();
    } catch (error) {
      // return error state
      return { error: error.message };
    }
  };

  const [state, submitAction, isPending] = 
         useActionState(submitHandler);


  return (
    <div>
      Add new User
      <form action={submitAction}>
        <div>
          Name: <input name="name" type="text" placeholder="Name" />
        </div>
        <div>
          Age: <input name="age" type="text" placeholder="Age" />
        </div>
        <div>
          <button disabled={isPending}>
            {isPending ? "Adding" : "Add User"}
          </button>
        </div>
        {error && <p>{error}</p>}
      </form>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • submitHandler: A function that handles the form submission by making an API call to create a new user.
  • useActionState: A new React 19 hook that manages the state and lifecycle of an asynchronous action. It provides [state, submitAction, isPending].
    • state: Contains the latest response from the handler function.
    • submitAction: A function that can be assigned to the action attribute of the form.
    • isPending: Indicates whether the async function is still running, useful for preventing duplicate submissions and providing UI feedback.

In this example, we create a form to add a user, using useActionState to handle the submission and manage the loading state.

preview of React 19 new features actions and related hooks

useTransition Hook

The useTransition hook is useful for managing transitions in UI states, particularly when performing minor async operations that don't involve forms.

export default function UserList() {
  const [users, setUsers] = useState([]);

  //Make API call to get the list of users
  useEffect(() => {
    getUserData();
  }, []);

  const getUserData = async() => {
      const response = await fetch("http://localhost:3000/users");
      const data = await response.json();
      setUsers(data);
  };

  return  (
    <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Age</th>
        </tr>
      </thead>
      <tbody>
        {users.map((user) => (
          <UserItem user={user} key={user.id} refreshCache={refreshCache} />
        ))}
      </tbody>
    </table>
  );
}


//User Item

export function UserItem({ user, refreshCache }) {
  const [isDeleting, startDeleteTransition] = useTransition();

  const deleteHandler = (userId) => {
    startDeleteTransition(async () => {
      const response = await fetch(`http://localhost:3000/users/${userId}`, {
        method: "DELETE",
      });
      refreshCache();
    });
  };
  return (
    <tr>
      <td>{user.name}</td>
      <td>{user.age}</td>
      <td>
        {isDeleting ? (
          <div>deleting...</div>
        ) : (
          <button onClick={() => deleteHandler(user.id)}>Delete</button>
        )}
      </td>
    </tr>
  );
}
Enter fullscreen mode Exit fullscreen mode

The useTransition hook helps manage the pending state during the deletion of a user, providing a smoother user experience.

useTransition hook to show pending state - preview

Conclusion

React 19 introduces some exciting new features for handling form submissions and asynchronous operations. These new hooks, like useActionState and useTransition, offer powerful alternatives to traditional methods and third-party libraries. However, only time will tell if they can fully replace established tools like React Hook Form or Formik.

For more information, check out the source repository.

And for understanding about Server Actions read my post

Top comments (0)