- ) form so you can see how child components update the parent component’s state, and how the parent then updates the child component via props ( unidirectional data flow ).
- The array of letters is joined again, and the new string is set to component state.
- All of the form element components in this post are pure functional components.
- Regular, or dumb, components receive data from their parent (container) component.
- The component is very similar to the components covered already.
This tutorial covers controlled form components, and best practices like immutability and unidirectional data flow. There’re plenty of examples to borrow and tweak for use in your own projects.
This post covers the following controlled components:
Also covered are:
The problem I came across when learning React.js was finding real-world examples of controlled form components. Examples of controlled text inputs are plentiful, but what about checkboxes? Radios? Selects?
Here is a list of real-world examples of controlled form components; it’s the list I wish I found early on in my React education. All form elements are represented here except for date and time inputs, which need a post of their own.
To speed up development time, sometimes it’s tempting to import a library for something like form elements. When it comes to something like forms, I’ve found that using library just makes life more difficult when I need to add custom behavior or validation. Once you know proper React patterns, creating form components isn’t difficult and it’s something we should all probably do ourselves. Please use the code in this post as inspiration or as a starting point for your own form components.
In addition to the code for individual components, I’ve put them all together in a (pet adoption!) form so you can see how child components update the parent component’s state, and how the parent then updates the child component via props (unidirectional data flow).
). It’s by far the easiest way to get set-up to build React apps.
What is a controlled component?
A controlled component has two aspects:
This is a one-way loop – from (1) child component input (2) to parent component state and (3) back down to the child component via props – is what is meant by unidirectional data flow in React.js application architecture.
, and here it is:
Interlude: container (smart) components vs (dumb) components
This is a good time to mention container (smart) components vs (dumb) components. Container components house business logic, make data calls, etc. Regular, or dumb, components receive data from their parent (container) component. Dumb components may trigger logic, like updating state, but only by means of functions passed down from the parent (container) component.
Note: I should point out that not all parent components are container components, but that’s how our form is set up. It’s perfectly fine to have a hierarchy of dumb components within dumb components.
lifecycle hook, and contains the logic for updating the state of the form. For the sake of simplicity, I’ve left out the props and change handlers of the form element components in the outline below. (Scroll to the end of the post for the complete code.)
Now that the basic architecture is laid out, let’s take a look at each child element.
input, depending on the props you pass it. A great way to document the props a component takes is via React’s PropTypes. If any props are missing, or if the prop is the wrong data type, a warning will appear in the browser console.
), and much more. (See the React docs for more details).
Let’s go through these one by one.
. All of the form element components in this post are pure functional components.
The select component (i.e. a dropdown), takes the following props:
attribute in your repeater/mapping function, but you’ll have warnings in your browser console and rendering performance will be compromised.
component above), and renders a set of form elements – either a set of checkboxes or a set or radios.
This is the most interesting component in our form. Here’s the code:
is a falsey value.
The handler function for this component is also more interesting that the others.
blocks. We declare it outside of these blocks so it is in the outer scope of the function and is accessible to all the blocks within.
This function has to handle two possibilities.
, but, rather, a new array is created. This practice of creating new objects and arrays rather than mutating existing ones is another best practice in React. This allows developers to more easily keep track of state change, and allows third party state management libraries like Redux to do highly performant shallow checking of data types rather than performance hindering deep checking.
. This method returns a new array (remember to avoid mutating in React!) containing all items that meet the filter condition.
In this case, all selections are being returned except for the one passed into the function.
‘s state changes.
in the case of our number input).
function clears the form.
In order to submit this form’s data, we construct an object out of the appropriate state properties. Then use an AJAX library or technique to send this data to an API (which is not covered in this post).
into an array of individual letters. Then the letter ‘e’ (or whatever character you would like to exclude) is filtered out. The array of letters is joined again, and the new string is set to component state. Not to bad!
This code above is in the repo for this post, but commented out, so feel free to tweak it meet your own purposes.
Admittedly, building controlled form components with React requires some repetition (e.g, the handler functions in the container), but the control you have over your app and the transparency of state change is well worth the up-front effort. Your code will be maintainable, and very performant.
If you’d like to be notified when I publish a new post, you can sign up for my mailing list in the navbar of the blog.