Hi everyone!
While developing applications using React, forms can sometimes pose significant challenges. In this article, I will share the essential features of React related to form handling and the points to consider when developing forms.
Forms are essential tools for user input and data collection in web applications. Proper management of forms is crucial for a good user experience and app performance. In this article, we will discuss the fundamental features of React related to forms and the necessary tools for developing efficient forms.
The flow of the article will be as follows:
- Form Handling w/Traditional Way (Client Side)
- Controlled / Uncontrolled Inputs
- Creating High-Performance Forms in Traditional Way
- Form Management Libraries
2. The New Age: Server Actions
- What Are Server Actions?
- Form Handling with Server Action
Form Handling w/Traditional Way (Client Side)
Until React 18, there is no chance to run our code outside the client. In this way, we should consider rendering, state management of forms and etc. for our app performance and UX.
This section will show you the essential fundamentals and best approaches for creating and handling performant forms in React Universe.
Before I continue, there is one point I want to make clear, rendering is not a beast; it is the backbone of React. However, redundant render is indeed a monstrous issue. As web developers, rendering is an essential aspect of our work, and when necessary, we should utilize it. Nonetheless, we must also safeguard our applications from unnecessary rendering to enhance performance. Therefore, this article does not advocate against rendering but rather focuses on optimizing the handling of web forms for improved performance.
Controlled / Uncontrolled Inputs
We can define the inputs we use in our forms in two ways. Let us learn from the below snippet:
These inputs do the same job as a result, but according to the chosen method, they directly affect the form management and app performance. If we compare them to understand their effects, we can write the following pros/cons table:
Controlled Component:
Pros:
- Maximum flexibility and customization.
- Easy data validation and error management.
Cons:
- Potential performance issues with large datasets or fast interactions.
Uncontrolled Component:
Pros
- Less configuration and easier to use.
- Performance advantage with large datasets or fast interactions.
Cons
- Sometimes increased code complexity with direct DOM manipulation and out-of-state data processing.
Creating High-Performance Forms in Traditional Way
As we have examined above, both approaches have advantages and disadvantages. While controlled components provide more flexibility and easier data validation, they have disadvantages such as performance issues and code complexity. Uncontrolled components, on the other hand, offer fewer configuration and performance advantages, while they can create disadvantages such as code complexity.
However, for creating performant forms, it is recommended to opt for the uncontrolled approach, which directly accesses DOM elements. By using uncontrolled components, there is no need to rely on React state or synchronize with it, allowing users to enter data directly into pure HTML inputs. This eliminates the need for state updates and UI re-renders, resulting in improved performance.
Let’s compare these two methods with a simple example without using any external library and examine the results.
The properties of the simple form we will use as an example:
In a controlled form, every user interaction triggers a re-render as the React state is updated. In a simple login form, even typing a single character can result in more than 25 renders until the form is complete.
In an uncontrolled form, there is no need for React re-rendering while inputting data. Instead, we instantly connect to the inputs using refs. The form data is accessed and validated only when the LOGIN button is clicked. If there are any errors, they are shown; otherwise, the submit operation is performed successfully.
In real-world scenarios, it’s common to use external libraries for handling form data, validating inputs, and other form-related tasks. To simplify form handling and tackle these challenges, popular React form libraries like Formik, React Hook Form, and Redux Form are available. These libraries expedite development, simplify form handling, and contribute to an improved form experience.
Form Management Libraries
The top 3 popular form libraries mentioned above offer advanced features for form functionality such as form validation, data management, form status tracking, error handling and more. They also provide support for components specific to form fields, custom validation rules, form submission, and data manipulation. By using these libraries, we can make more complex form scenarios easier to manage and provide a better user experience.
However, there are some fundamental differences between these libraries. These differences are specified in the React Hook Form documentation as follows:
As can be seen from the table above, React Hook Form is the library that attaches the most importance to performance among these libraries. The most important feature of its good performance compared to other libraries is that it uses an uncontrolled component approach which we mentioned before as necessary to create a performant form. This makes the values and states of the form elements accessible via refs without directly binding them to the React state. This is very performance advantageous because it does not have to update the React state every time the user inputs or changes a value. I recommend you review the very well-prepared documentation.
In conclusion, when it comes to client-side forms, opting for an uncontrolled component approach can greatly enhance performance. You can create your forms as uncontrolled, leveraging the benefits of this approach for improved efficiency. However, if you have complex requirements such as form validations, advanced form handling logic, and seamless integration with validation libraries, you’ll need a reliable tool for managing client-side forms in React applications. In such cases, React Hook Form emerges as a powerful and efficient solution. It not only prioritizes performance but also provides comprehensive form-handling capabilities, including robust validations and seamless integration with popular validation libraries.
The New Age: Server Actions
Server actions are a powerful new feature in React that allows you to run asynchronous code on the server in response to user interaction. Even though it’s mostly a new feature, there’s no doubt it’ll be a game changer. NextJS currently (13.4) supports this feature experimentally.
So What Are Server Actions?
In the context of React, server actions are functions that are executed on the server before the page is rendered on the client. They can be used to perform a variety of tasks, such as:
- Pre-validating form data
- Saving form data to the server
- Making API requests
- Pre-rendering pages
- Generating dynamic content
- Caching data
In NextJS 13.4 this feature supports as an alpha feature. They offer a robust foundation for implementing server-side functionalities. Next.js API routes provide a way to create custom server endpoints that handle specific actions and data operations.
In order not to go beyond our topic, we will deal with the parts related to forms here.
Form Handling with Server Action
Server actions are defined through the action prop on <form/>. Typically, when building HTML forms, you pass a URL to the action prop. With server actions, Next now allows you to pass a function directly.
When a server action is triggered, the function is executed on the server and the result is returned to the client. This means that the form can be interactive before any client-side JavaScript has loaded. This is a great way to improve the performance of your applications.
Here is an example for better understanding:
The above sample is a server component with server actions, which means that all of the logic is executed on the server. We use ‘use server’ keyword top of our action function scope to tell that Next.js should execute this function on the server.
This means that the form can be rendered and interacted with in the browser even if JavaScript is disabled. This is very important because it means that things like rendering, validation, form state and bundle size that we talked about in previous parts of the article, which we should consider for performance forms, are no longer important considerations.
You can keep all of the complex logic of forms on the server and manage the form on the server anymore. This feature is currently in the experimental stage but will be stable very soon. After that, we will have to completely rethink how we should handle our forms.
Since it is very new now, it is not entirely possible to handle forms with these features in the traditional way. In particular, we cannot do the validation strategy that we use as a sample before in this article with the server component + server action pair. However, NextJS allows server actions to be used with client components as well.
Let’s see how we can develop a validation closer to our needs with these new features with an example:
We used server action for form handling with minimum client JS which was able to render a success state and input errors.
I have kept the examples simple like this for easy understanding, but you can add event listeners here and manipulate the error state according to your needs. But remember, every client-side code like onChange listener will require you to pay attention to the performance issues that we have explained in the above section of the article.
You can access all the examples you see in this article and more from the links below:
Live demo | Github Repo | CodeSandbox
Conclusion
In this article, we examined the points we should consider while developing with React/Next.js and the methods we can use for more performance forms.
Dealing with react-hook form seems to be the best solution at the moment due to the difficulties, flexibility and performance of forms on the client side. The new experimental feature server-action is very exciting and definitely looks like it will cause us to completely rethink/design the traditional methods we use.
Until we meet again, stay in tech.
Oğuzhan Sofuoğlu
Frontend Developer @ÇSTech
Github | Linkedin | Personal Website
References:
- https://react-hook-form.com/get-started
- https://react.dev/reference/react
- https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions
Optimizing Form Handling in React: Maximizing Performance was originally published in ÇSTech on Medium, where people are continuing the conversation by highlighting and responding to this story.