The Untold Story of Form Submissions in React 18
Tags: serveractions, form, react, onsubmit
Published: 2023-12-28 10:45:22

_In this article you will discover and learn how `OnSubmit` and `action` props work together. You will also learn how you can perform other actions before and after invoking a *server action* in a form element of a React component._

## Introduction

In traditional React apps, the common props for handling forms are `onChange` and `onSubmit` props. These props enables a developer to handle and track users as they interact with the forms. The `onChange` prop enables tracking of user entry on a form field. The `onSubmit` prop allows the developer to specify a function that will be executed when the form is submitted. This function can perform actions such as validating the input, sending data to a server, or displaying a message to the user.

## Understanding the `onSubmit` prop

The onSubmit prop is passed to the form element as an attribute, and it expects a function as its value. 

```javascript
//line

<form onSubmit={handleSubmit}>
//form content
</form>
```

In a basic form, the function can take one parameter value. The value's parameter contains the data entered by the user in the form fields. The function can perform actions such as:

 * Validating the input.
 * Sending data to a server.
 * Displaying a message to the user.

 The following code snippet provides a list of possible actions, that can be carried out by an `onSubmit` handler in a form that prompts a name and email of user:

```javascript
// handle the submit event of the form
const handleSubmit = (event) => {
  // prevent the default browser behavior
  event.preventDefault();
  // validate the input and submit the form
  if (name && email && message) {
    // reset the form fields to their initial values
    // store the input data in the local storage or a database
    // send an email or a notification to the user or someone else
    // update the state or the UI of the app based on the input data
    // call an API or a web service with the input data
    // redirect the user to another page or URL
  } else {
    alert('Please fill all the fields');
  }
};

```

From the code snippet above, you can perform several actions after form submission, including:
1. Sending emails.
2. Notifying user.
3. Updating the UI  
4. Redirecting user to another URL.

However, with the coming in of React Server Components, the form submission process in React has taken a turn by the introduction of the `action` prop to submit form data.

## Using the `action` Prop to Submit Forms in React

Just like the `onSubmit` prop , the `action` prop allows form submission by passing an ordinary function or Next.js' server action to it as a value . Since React 18, you can make use of the `action` prop to submit forms in both  React server and client components.

The `action` prop does not replace the `onSubmit` prop but rather it integrates with it. The action prop allows you to invoke a server action on a `<form>` element, which can perform server-side data mutations or actions without creating separate API routes.

The `onSubmit` prop allows you to specify a function that will be executed after the server action is completed, and receive the value returned by the server action as a parameter. The `action` prop and the `onSubmit` prop work together to provide a seamless and performant experience for form submissions and data mutations in Next.js applications.


```javascript
import { SubmitButton } from '@/app/submit-button'
import { createItem } from '@/app/actions'
 
// Server Component
export default async function Home() {
  return (
    <form action={createItem}>
      <input type="text" name="field-name" />
      <SubmitButton />
    </form>
  )
}
```

In the code above, the `createItem` can be an ordinary function or a server action which is an `async` function.  However any function specified in the action, receives a `formData` value as submitted from the form. 


If `createItem` is a simple function, it can do the some of the following logic:

```javascript
// define an ordinary function to create an item
function createItem(formData) {
  // use the formData value to get the input data
  // perform any validation or processing on the input data
  // send the data to an API
  // return a value or an error
}
```

If `createItem` was a server action then it may perform some of the following logic:

```javascript
// define an async function to create an item
async function createItem(formData) {
  // use the formData value to get the input data
  // perform any validation or processing on the input data
  // use await to send the data to a server or a database
  // send the data to an API
  // return a value or an error
}
``` 

## Integrating `onSubmit` and `action` props on the form element.

Out of curiosity, one may ask: Is it possible to use both `onSubmit` and the `action` prop together in a form component?


Yes, you can use the `onSubmit` and `action` prop together on a `<form>` element in Next.js 14. The `action` prop allows you to invoke a server action, which is an async function that can perform server-side data mutations or actions without creating separate API routes. The `onSubmit` prop allows you to specify a function that will be executed after the server action is completed, and receive the value returned by the server action as a parameter.

The logic and the experience of using the `onSubmit` and `action` prop together are as follows:

- When the user submits the form, the `action` prop invokes the server action with the form data as an argument.
- The server action performs the desired action on the server, such as sending data to a database, calling an API, or validating the input. The server action can also return a value or an error.
- The `onSubmit` prop receives the value or the error returned by the server action, and executes the function specified by the `onSubmit` prop. The function can perform actions such as displaying a message to the user, redirecting the user to another page, or updating the state or the UI of the app based on the value or the error.
- The user sees the result of the form submission and the server action, and can interact with the app accordingly.

Here is an example of using the `onSubmit` and `action` prop together on a `<form>` element in Next.js 14:

```jsx
// app/actions.js
'use server'
export async function createItem(formData) {
  // perform server-side data mutation or action
  // return a value or an error
}



// app/client-component.jsx
'use client'
import { createItem } from './actions'
export default function ClientComponent() {
  // define a function to handle the onSubmit event
  const handleSubmit = (value, error) => {
    // perform actions based on the value or the error
    // such as displaying a message, redirecting, or updating the UI
  }
  return (
    // use the action prop to invoke the createItem server action
    // use the onSubmit prop to handle the value or the error returned by the createItem server action
    <form action={createItem} onSubmit={handleSubmit}>
      <input type="text" name="name" />
      <button type="submit">Create Item</button>
    </form>
  )
}
```


## Performing Actions Before and After Invoking a Server Action Using the Action Prop.

When using server components, you may want to perform some actions before or after a server action is invoked. For example, you may want to show a loading indicator, validate the input, or display a success or error message. You can use the `action` prop to pass a simple function that can perform these actions and invoke the server action. The function can take one parameter: formData.

 The formData parameter contains the data entered by the user in the form fields. The function can use the `await` keyword to invoke the server action and wait for its completion. The function can also return a value or an error that will be passed to the `onSubmit` prop of the form, if it is defined.

Here is an example of using the `action` prop to pass a simple function that performs actions before and after invoking a server action:

```jsx
// app/server-component.jsx
export default function ServerComponent() {
  // define a server action that sends a message
  async function send(message) {
    'use server'
    // perform server-side data mutation or action
    // return a value or an error
  }

  // define a function that adds an optimistic message to the UI
  function addOptimisticMessage(message) {
    // update the UI with the message
  }

  // define a function that shows a toast notification
  function showToast(message, type) {
    // show a toast notification with the message and the type (success or error)
  }

  // define a function that redirects the user to another page
  function redirect(url) {
    // redirect the user to the url
  }

  return (
    // use the action prop to pass a simple function that performs actions before and after the server action
    <form
      action={async (formData: FormData) => {
        // get the message from the formData
        const message = formData.get('message');
        // add an optimistic message to the UI
        addOptimisticMessage(message);
        // invoke the server action and wait for its completion
        try {
          const value = await send(message);
          // show a success toast notification
          showToast('Message sent successfully', 'success');
          // redirect the user to another page
          redirect('/thank-you');
          // return the value to the onSubmit prop
          return value;
        } catch (error) {
          // show an error toast notification
          showToast('Message sending failed', 'error');
          // return the error to the onSubmit prop
          return error;
        }
      }}
    >
      <label>Message:</label>
      <input type="text" name="message" />
      <button type="submit">Send</button>
    </form>
  );
}
```


## Conclusion

This article has covered how forms are submitted in traditional React apps, the props used to handle forms and how the value of the props. The article has also covered the how to integrate the  `action` and `onSubmit` props to create a progressive form with a better user experience. Finally, it has also covered the how you can perform other logic before and after you have invoked a server action in Next.js 14 and above. If you may have any questions please feel free to ask in the comment box or reach out to me via twitter a.k.a X.(You can check for my handles in my profile)