Many large-scale enterprise applications — both internal and external — require a substantial amount of form handling. It acts as the means by which users provide the data that feeds into the engine of a system and which can later be analysed in such a way that reports are innovatively generated and presented to stakeholders or customers for various purposes.
From a UX/CX and business point of view, it is important that form handling is achieved in such a way that users are content to provide a complete and accurate set of data in a trusting and timely manner and without frustration or difficulty. Failure to ensure this may result in a user providing the bare minimum (or even worse, inaccurate) information in order to get through the form stages as quickly as possible. Bad data leads to bad products and bad business.
React provides the means to create highly efficient application front-ends. Used with a state management tool, such as Redux, an intelligent and efficient form, with various input types and validation rules, can be successfully created in order to meet the requirements that are outlined above. However, depending on the form and its size, this may come with a costly level of verbosity. Large-scale applications often require very comprehensive and intricate workflows for their forms, with complex validation rules.
In these scenarios, creating an efficient form handler, whilst very possible, can be costly from a development perspective. Whilst a good level of efficiency can be ensured by creating form fields as reusable components or higher-order components and by creating a set of useful utility functions, costs can be attained through length and disparity of code. In order for the React form to be properly functional, the various fields must be connected to the state. Redux-form is a very good library that enables the creation of effective forms in this manner. It has established itself as the standard way of doing so. However, it comes with some frustrating (and significant) performance costs: as the fields are updated, performance overhead grows as state is updated. This is especially the case in larger applications.
Since 2018, a particular library for form creation and handling has grown immensely in popularity, as it addresses the aforementioned costs in a very effective way. Formik is a small and nifty library (it is 12.7 kB as opposed to Redux-form’s 22.5 kB) developed by Jared Palmer. One of its guiding principles is Dan Abramov’s belief that form input state should not be tracked in Redux and that it is inherently local (https://github.com/reactjs/redux/issues/1287#issuecomment-175351978). Therefore, connecting it to Redux should not be seen as necessary. The other principle motivation is the serious performance issue described above, whereby state is updated every time an input field is updated.
Formik handles form data locally and connects it to state only at a local level. It is inputted as a component (
<Formik />) and the form is configured through a set of props that are then passed to it. These include the initial values (
initialValues) for the fields, validation rules (
validate), and event handlers (
handleSubmit). Of course, some of these may be imported as utility functions or components, depending upon the requirements of the application. Inside of the
handleSubmit function, a Formik function called
setSubmitting is typically called at the end by passing the boolean
false to it, telling the
<Formik /> component that submission has completed.
Some of the nice features of Formik include some components that come with it in order to reduce the verbosity of the code even further:
<Field /> and
<ErrorMessage />. These must each be imported from Formik alongside the
<Formik /> component.
<Form /> wraps a HTML
<form /> element and automatically hooks Formik’s
handleReset functions to it. By default,
<Field /> renders as a HTML
<input /> element. But by specifying a
type, this can be altered. Alternatively, a custom component can be specified here with the
<ErrorMessage /> renders the specific error message for a particular field, but only if the field in question has been touched and an
error message exists for that field (as specified in the Formik
validate prop that is mentioned above).
In relation to validation with Formik: whilst not required, Yup is supported by Formik for this purpose. Indeed, Yup is what is actively used by the developers of Formik. In a case where this or another third-party validation library is preferred for use with Formik, a
validationSchema prop should instead be utilised in place of the
validate prop for the
<Formik /> component. The value that is passed to this
validationSchema prop can be a function which calls this third-party library.
Thus, the developmental advantages offered by Formik are substantial and as such, are matched by advantages to the business.