DEV Community

Cover image for React built-in hooks: useActionState
Richard Choi
Richard Choi

Posted on • Edited on

React built-in hooks: useActionState

This is the start of my React built-in hooks series, where I took some time to look at the React docs and have a deeper look into each respective built-in hook, even the ones I'm already very familiar with.

useActionState has some interesting use cases where it provides a way to store your state along with a loading transition for the action callback you pass for the form to trigger upon submission.

What this means is that by using a server function to grab your form input values by their unique name attributes, you're able to tell the code to wait for the form submission action to be completed before you're able to see the updated data.

Here is my demo, where you can see it in action (hehe). The code informs the user that it's currently loading until the form submission is complete. You can see this demonstration with the failed request in a delayed time to observe it in action and how quickly it runs without delay.

Image description

app/page.tsx

"use client"
import React, {useActionState} from "react";
import {addToCart} from "./hooks/addToCart";

export interface ICart {
  itemID: string,
  itemTitle: string,
  itemPrice: number,
  itemQuantity: number
}

export const cart: ICart[] = [];

function AddToCartForm({itemTitle, itemID, itemPrice}:{itemTitle: string, itemID: string, itemPrice: number}) {
 const [cartItem, cartAction, isPendingCart] = useActionState(addToCart, {itemTitle: "", cartID: "", itemPrice: 0, itemQuantity: 0});

  return (
      <form action = {cartAction}>
      <h2>{itemTitle} ${itemPrice}</h2>

      <input type="hidden" name="itemID" value={itemID} />
      <input type="hidden" name="itemTitle" value={itemTitle} />
      <input type="hidden" name="itemPrice" value={itemPrice} />
      <label>Add number of items to cart: </label><input type="number" name="itemQuantity"/>

      <button type="submit">Add to Cart</button>
      <span>{cartItem.message}</span>

      {isPendingCart ? "Loading..." : <section>
        <h2>{cartItem.itemTitle}</h2>
        <h4>{cartItem.total}</h4>
        </section>}
      </form>
  );
}

export default function Home(){
  return(
    <main>
      <AddToCartForm itemTitle={"Hatsune Miku shirt"} itemID = {"1"} itemPrice={12.12}/>
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

app/hooks/addToCart.ts

"use server"

export async function addToCart(prevState, queryData){
  const itemID:string = queryData.get('itemID');
  const itemTitle:string = queryData.get('itemTitle');
  const itemPrice:number = queryData.get('itemPrice');
  const itemQuantity:number = queryData.get('itemQuantity');

  const message = "Item was added to cart!"

  if (itemID && itemTitle && itemPrice && itemQuantity > 0) {
    const total = itemPrice * itemQuantity
    return {itemID, itemTitle, itemPrice, itemQuantity, message, total};
  } else {
    // Add a fake delay to make waiting noticeable.
    await new Promise(resolve => {
      setTimeout(resolve, 2000);
    });
    const total = itemPrice * itemQuantity
    const message = "Enter a valid quantity!"

    return {itemID, itemTitle, itemPrice, itemQuantity, message, total};
  }
}
Enter fullscreen mode Exit fullscreen mode

My hope with this series is to bring underrated built-in hooks to light, as well as highlight some things you may not have known about familiar hooks.

Top comments (10)

Collapse
 
dotallio profile image
Dotallio

Really enjoying this deep dive into underrated hooks, useActionState's loading feedback is something I've overlooked in my own forms. Are you planning to cover useOptimistic or any other newer ones next?

Collapse
 
choir241 profile image
Richard Choi

Glad to hear that!! Indeed, I plan on covering all of them hahhahaha

Collapse
 
nevodavid profile image
Nevo David

Love when someone actually goes deep on the less flashy hooks - makes me want to poke around with useActionState more myself.

Collapse
 
choir241 profile image
Richard Choi

You definitely should experiment around useActionState more!!! It was fun using it and learning more about it.

Collapse
 
deividas_strole profile image
Deividas Strole

useActionState is a handy hook for managing state updates based on user actions, especially in forms. It's a great addition for cleaner and more predictable state transitions.

Collapse
 
choir241 profile image
Richard Choi

For sure!!! I love how much more clean my code looks~

 
choir241 profile image
Richard Choi

I have a twitter or linkedin if you want to chat :)

Collapse
 
choir241 profile image
Richard Choi

Thank you!! Likewise ^^