Skip to content

Form Actions

Within a component you might need to respond to an event (for example a click) with an event handler that must trigger something on the server.

Very common pattern:

import { useState } from 'react'

export const Demo = () => {
  const [fullName, setFullName] = useState('')

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    await fetch('<https://api.example.com/submit>', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ fullName }),
    })
  }

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type='text'
          value={fullName}
          onChange={(e) => setFullName(e.target.value)}
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

Same example, using FormData, which removes the need to track each individual input field value using a state management tool (useState in the above example):

import { useRef } from 'react'

export const Demo = () => {
  const formRef = useRef<HTMLFormElement>(null)

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()

    if (formRef.current) {
      const formData = new FormData(formRef.current)

      await fetch('<https://api.example.com/submit>', {
        method: 'POST',
        body: formData,
      })
    }
  }

  return (
    <div>
      <form ref={formRef} onSubmit={handleSubmit}>
        <input
          type='text'
          name='fullName'
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

The same thing now can be performed using an action:

export const Demo = () => {
  async function myFormAction(formData) => {
    await fetch('<https://api.example.com/submit>', {
      method: 'POST',
      body: formData,
    })
  }

  return (
    <div>
      <form action={myFormAction}>
        <input
          type='text'
          name='fullName'
        />
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

Look how much simpler the code is, because now we don’t track the individual input fields state, but also we don’t respond to a browser event directly, and we don’t have to pass the form ref around to keep track of how to access it, because the actions is directly passed the FormData object.


→ Get my React Beginner's Handbook

→ I wrote 17 books to help you become a better developer:

  • C Handbook
  • Command Line Handbook
  • CSS Handbook
  • Express Handbook
  • Git Cheat Sheet
  • Go Handbook
  • HTML Handbook
  • JS Handbook
  • Laravel Handbook
  • Next.js Handbook
  • Node.js Handbook
  • PHP Handbook
  • Python Handbook
  • React Handbook
  • SQL Handbook
  • Svelte Handbook
  • Swift Handbook
...download them all now!

Also, JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025

Bootcamp 2025

Join the waiting list