Frontend
.......................................................................................................
Signup to be notified when the Fluent React course
launches in MARCH 2025 .
(and get started with a 5-part free React course in the mean time.)
...........................................................................................

What You will Learn

In this developer guide, you will learn:

 

  • About the built-in state management hook: `useState()` and how to use it to manage your React components' state.

  • How to build forms in React and associate form input with pieces of the component's local state.

  • How to build working forms using JSX, event listeners and proper event handlers (to take care of the data entered into the form.)

  • How to use the form data submitted by your app's user to set the state of your React component

  • About best practices to follow and gotchas to avoid as you implement form processing in your React apps.

 

And, so, without more fluff or fillers, let's get into building forms and handling form input data and events in your React components.

 

1: Intro

 

One of the most common interactions your React app (or any web app, for that matter) will see will be taking input from your app's users. This will usually take the form of the user filling out form fields on the pages of the app. These could be your registration, login, comment or file/photo upload forms.

 

So, how do you handle user input and form processing in your React app's components?

 

And, how do you keep track of the values of the user's input into your form fields?

 

And, how do you set or update the values of your React component's local state based on the data entered into the form (such that the component's state is bound to the user's form input)?

 

That's what we will cover in this developer guide.

 

So, let's get started.

 

2: Create the App

In this section, we will:

  • Install React

  • Start a new React app

  • Create some custom components for the app

  • Create the component that will hold our user registration form

  • Add some event listeners and handlers to process the user's form input and bind it to the component's local state

  • Apply some very basic CSS styling to the JSX markup

 

So, let's get coding ...

 

2.1: Setup the App's Structure

Before we build any components we first have to create the React app.

 

If you haven't done this before, you can follow the "Let's Create Our First React App" guide for a step-by-step walkthrough of how to properly create a React app and learned how to properly structure its various parts (components, routes, API-calling files, etc.)

 

But, in summary, you should:
 
  • Install ReactJS

  • Open your terminal

  • Run `create-react-app my-app` (where `my-app` is the name of your React app. Replace it with your own app's name)

  • Once the React files and boilerplate are generated:

    • cd into the `src/` directory of the React app you just created

    • Create a new `components` folder inside the `src/` directory with: `mkdir components`

 

Once you have created the React app, come back here and let's continue.

 

2.2 Create the App's Custom Components

Once you have created your React app, next, create the `Home`, `Header` and `Footer` components inside your app's `src/components/` folder. These components are not strictly necessary, but are a good practice since you will need them in almost any serious React app. So, create those components, too. See the "Let's Create Our First React App" guide for how to do this if this is your first rodeo.

 

2.3 Create the Form Component

Before we move on, let's be clear about what we want to build.

 

We want to create a component that lets a visitor to your app register for a new account on the website.

 

So, this component will have a form with fields that include:
  • firstName
  • lastName
  • email
  • password

 

We won't focus much on styling, complex state management, API calls and other aspects of building a React app's component. This is because we want to focus mainly on how to properly build React forms and how to handle form input and events in your React components.

 

So, without much ado, let's get coding ...

 

`cd` into the `src/components/` directory of your app folder and create a `NewUser.js` file which will hold the `NewUser` component's code.

 

Next, let us start work on the `NewUser` component by:

  • setting up the component with the proper imports

  • setting up the local state of the component

  • starting a (minimal) form. (We will work on this form in more detail in the following sections.)

 

So, after implementing the above steps, your `src/components/NewUser.js` component file should now look like this:

 


    import React, {useState} from 'react'

    const NewUser = () => {
      return (
        <div style={{ margin: '25px'}}>
            <h3 style={{ marginLeft: '25%' }}> Register for a New Account </h3>
            <p>
                Fill out the form below to sign up for a new account on this website.
            </p>
            <form>
                <p>
                    <label> First Name </label>
                    <input 
                        type='text'
                        placeholder='First Name'
                        style={{ marginLeft: '15px'}}
                    />
                </p>
                <p>
                    <label> Last Name </label>
                    <input 
                        type='text'
                        placeholder='Last Name'
                        style={{ marginLeft: '15px'}}
                    />
                </p>
                <p>
                    <label> Your Email </label>
                    <input
                        type='email'
                        placeholder='Your Email' 
                        style={{ marginLeft: '15px'}}
                    />
                </p>
                <p>
                    <label> Password </label>
                    <input
                        type='password'
                        placeholder='Your Password'
                        style={{ marginLeft: '15px'}}
                    />
                </p>
                <p>
                    <input 
                        type='submit'
                        value="Create Account"
                        style={{ marginLeft: '45px'}}
                    />
                </p>
            </form>
    
        </div>
      )
    }
    
    export default NewUser
 
Up till this point, we have built our `NewUser` component to:

  • Have a `<form>` element to hold the various input elements of the form

  • Have instances of the HTML `<input />` element for each of our component's local state

  • Use some barebones CSS styling for the form and its input elements

 

But, at this point, what we have is just a vanilla HTML form with no React data binding or validation logic added to it.

 

So, let's change up the component JSX markup a bit ...

 

2.4: Add Component Local State and Handle Form Events

So, let's add and set some pieces of state for the `NewUser` component. We should also handle some of the form events related to changes in the form input.

 

To do that, we will:
 
  1. Define the pieces of the component's local state. These will be the firstName, lastName, emailAddress and password states/data. We will use the built-in React `useState()` hook to define the component state.

  2. Bind each of the user-entered form data (in the input elements) to a corresponding piece of the component's local state defined in the previous step.

  3. Add an event listener to each of the input elements of the form so that we can detect when the value of the input element changes so that we can set the value of the component state (that the changed input element is bound to) to the new value of the input element that the user entered.

 

So, let's get to updating our `NewUser` component to incorporate these proposed necessary changes.

 

Your `NewUser` component should now look like this:

    import React, {useState} from 'react'

    const NewUser = () => {
    
      const [firstName, setFirstName] = useState('')
      const [lastName, setLastName] = useState('')
      const [emailAddress, setEmailAddress] = useState('')
      const [password, setPassword] = useState('')
    
      return (
        <div style={{ margin: '25px'}}>
            <h3 style={{ marginLeft: '25%' }}> Register for a New Account </h3>
            <p>
                Fill out the form below to sign up for a new account on this website.
            </p>
            <form>
                <p>
                    <label> First Name </label>
                    <input 
                        type='text'
                        placeholder='First Name'
                        style={{ marginLeft: '15px'}}
                        value = {firstName}
                        onChange = {(e) => setFirstName(e.target.value)}
                    />
                </p>
                <p>
                    <label> Last Name </label>
                    <input 
                        type='text'
                        placeholder='Last Name'
                        style={{ marginLeft: '15px'}}
                        value = {lastName}
                        onChange = {(e) => setLastName(e.target.value)}
                    />
                </p>
                <p>
                    <label> Your Email </label>
                    <input
                        type='email'
                        placeholder='Your Email' 
                        style={{ marginLeft: '15px'}}
                        value = {emailAddress}
                        onChange={(e) => setEmailAddress(e.target.value)}
                    />
                </p>
                <p>
                    <label> Password </label>
                    <input
                        type='password'
                        placeholder='Your Password'
                        style={{ marginLeft: '15px'}}
                        value = {password}
                        onChange={(e) => setPassword(e.target.value)}
                    />
                </p>
                <p>
                    <input 
                        type='submit'
                        value="Create Account"
                        style={{ marginLeft: '45px'}}
                    />
                </p>
            </form>
    
        </div>
      )
    }
    
    export default NewUser

 

3: Handle Form Submissions and Form Data Validation

Next, let's decide on what to do when a user hits the "Create Account" button to submit the form's data.

 

To do that, we will:
 
  • Add an event listener to the root `<form>` element itself to detect/listen for when the form is submitted. This will trigger calling an event handler (a function) to validate and process the form data that was submitted by the user.

  • Create a function to handle the 'submit' event (which gets triggered when the "Create Account" button is clicked on). This function is what's called an event handler. As the name suggests, it contains the code/logic for handling an event that happens in the component/DOM.

 

In the previous step, we implemented our event handlers (for the `onChange` event listeners) for the input elements inline (i.e. within the JSX markup itself). But because the logic for the `onSubmit` event listener is a bit more complex, it is better handled in an external event handler function instead of inline.

 

So, update the component to include these new updates:

    import React, {useState} from 'react'

    const NewUser = () => {
    
      const [firstName, setFirstName] = useState('')
      const [lastName, setLastName] = useState('')
      const [emailAddress, setEmailAddress] = useState('')
      const [password, setPassword] = useState('')
    
      function submitForm(e){
        e.preventDefault() // To prevent submitting the form to the current page's URL
        // Check if all the form fields contain valid input data
        if(firstName && lastName && emailAddress && password){
            const newUserData = {
                firstName: firstName,
                lastName: lastName,
                emailAddress: emailAddress,
                password: password
            }
            // Ideally, we will make an API call to our backend API server to submit these form data (i.e the JSONified newUserData object).
            // But since we do not have an API server to work with (in this example, at least),
            // we will just console log the form data.
            console.log(`firstName: ${firstName}, lastName: ${lastName}, email Address: ${emailAddress}, password: ${password}`)
        }
      }
    
      return (
        <div style={{ margin: '25px'}}>
            <h3 style={{ marginLeft: '25%' }}> Register for a New Account </h3>
            <p>
                Fill out the form below to sign up for a new account on this website.
            </p>
            <form onSubmit={submitForm}>
                <p>
                    <label> First Name </label>
                    <input 
                        type='text'
                        placeholder='First Name'
                        style={{ marginLeft: '15px'}}
                        value = {firstName}
                        onChange = {(e) => setFirstName(e.target.value)}
                    />
                </p>
                <p>
                    <label> Last Name </label>
                    <input 
                        type='text'
                        placeholder='Last Name'
                        style={{ marginLeft: '15px'}}
                        value = {lastName}
                        onChange = {(e) => setLastName(e.target.value)}
                    />
                </p>
                <p>
                    <label> Your Email </label>
                    <input
                        type='email'
                        placeholder='Your Email' 
                        style={{ marginLeft: '15px'}}
                        value = {emailAddress}
                        onChange={(e) => setEmailAddress(e.target.value)}
                    />
                </p>
                <p>
                    <label> Password </label>
                    <input
                        type='password'
                        placeholder='Your Password'
                        style={{ marginLeft: '15px'}}
                        value = {password}
                        onChange={(e) => setPassword(e.target.value)}
                    />
                </p>
                <p>
                    <input 
                        type='submit'
                        value="Create Account"
                        style={{ marginLeft: '45px'}}
                    />
                </p>
            </form>
    
        </div>
      )
    }
    
    export default NewUser
 
And, that, in a nutshell, is how you do form processing and handle form events in React.

 

There is more to it than what we covered. But our coverage here accounts for more than 90% of what you need to do when working with forms in your React components.

 

But before we wrap up this show, let's take a tour of some things that you need to know (even if you don't need to apply them in every form processing case in your React components).



4: Form Event Handlers: Inline or External?

In our example `NewUser` component's form, we had to write JavaScript code to handle form events that were emitted as the user interacted with the form on the page.

 

We did the event handling in two ways:

  • Inline: This is when the function that handles the DOM event is written within the JSX markup of the component. In our case, we wrote the event handlers for all the `change` events of the `<input />` elements within the JSX markup. We used the `onChange` event listener to listen for whenever the `change` event is emitted on any of the `<input />` elements of the form.

    When the event handling code is written within the body of the component's JSX markup, it is referred to as being inline.

  • External Event Handling: Sometimes, the logic for what to do with an event that was triggered in your component may be too complex or multi-pronged/faceted that it won't be practical to write inline (i.e within the JSX markup). In such a case, it will be best to create a JavaScript function within the component but outside the component's `return()` statement. That is what we did with the `submitForm()` event handling function.

 

To handle an event using an external function, you have to:

  • add an event listener to the DOM element that you want to listen to. In our case, we are using the `onSubmit` event listener on the root `<form>` element.

  • pass the external event handler (function) in a pair of curly braces {} to the event listener.

 

This is why we added to the `<form>` element this chunk:

    <form onSubmit={submitForm}>
 
Note that you should not invoke the event handler by passing in the function with a pair of parentheses, like this:

    <form onSubmit={submitForm()}>

That will be a catastrophe waiting to happen ... because as soon as your component loads, the `submitForm()` event handler will be invoked and its body will be executed. So, you may have a bunch of errors from the function executing prematurely (because, in our example, none of the component's pieces of state has assigned values when the component first loads/mounts).

 

So, instead, pass in the event handling function without the parentheses, just like we did in our `NewUser` component's code.

 

So, depending on the simplicity or complexity of your form logic, pick either an inline or external approach to handling form events in your React component. If it simple enough, don't bother creating an external function; handle it inline.

 

If it is more complex or requires a bunch of things to be done (whether sequentially or simultaneously) after the (form) event is emitted, then, create an external JavaScript function (within your component's body) and implement the form event handling logic in there. Then, pass the event handler function's name to the event listener on the DOM element you are listening on.

 

As you build more and more React apps with different form-processing logic, you will intuitively start to realize which approach to take in each case.

 

5: What to Do After Processing a Form

Once your user hits the "submit" button and your event handler captures and processes the input from the form, what do you do next?

 

Depending on the needs of your application, your user experience and other factors, you can handle what to do after a form submission in a number of ways:

 

  • Make an API Call to Submit the Form Data: If you have a backend API server that takes your frontend app's component data and save it to a database, then you should make an API call over HTTP to your backend server and send the JSONified form data to your backend API server.

    If you are not familiar with how to make API calls from your React app, please, see the "Learn How to Use the `axios-http` Library in your React App to Make API Calls over HTTP to your Backend Server" guide where I go into details about how to do just that. That guide covers how to make API calls from your React app using the `axios-http` library and using reusable JavaScript classes.

    If you prefer to use the `Fetch API` to make API calls and/or would prefer creating custom hooks (instead of classes) to make API calls from your React app, then, see the "Create a Custom Hook to Make CRUD API Calls using the Fetch API" guide for details on how to do that.

  • Re-Render the Component: Your UX needs may necessitate that you re-render the component to display a confirmation message or any error messages you may get after trying to process the submitted form data. In this case, you may need to make use of the built-in `useEffect()` hook to listen for changes in the component's state and then re-render the component when there are changes.

  • Redirect to a Different Page: Sometimes you may just need to redirect the user to a different page once he/she successfully submits a form. This is useful, for example, when you need to redirect a user to a "Member's Area" or a section of the site that's only accessible by authenticated and/or authorized users.

 

The react-router-dom package has components and hooks that can help you redirect users to a specified page after submitting a form. See the official docs for a details on how to do that.

 

6: Gotchas when Doing Form Processing in React

No matter how meticulous you try to be, you will encounter some warnings, bugs and/or errors when developing form components in React. Consistent practice is the most surefire way to develop expertise and avoid the "gotchas" that await anyone new to React or any other web development framework, whether backend or frontend.

 

So, here are a few common gotchas that you can learn from to be better equipped to process forms in your React app's components.

 

These include:
 
  • No Event Listener on an Input Element: You may forget to add an event listener property on a form's input element. This input element could be an `<input />`, `<textarea>`, `<select>` or other form input elements.

    Usually you would put an `onChange` event listener on the element and pass an event handler to it in a pair of curly { } braces (either inline within the JSX markup or as an external JavaScript function).

    If you forget to add the event listener to the input element, the related/bound piece of component's local state will never be set and your form won't validate and you may get other related errors.

    So, make sure that every one of your form's input element has an `onChange` event listener on it and that there is a valid event handler passed to it (whether inline or as an external function.)

  • No Event Handler Attached: This is related to the first gotcha above. Sometimes, you may add the `onChange` event listener on an input element but then forget to pass it a valid event handler.

    This means that, while your component may listen for changes on your form, it will do absolutely nothing about it ... because you didn't pass it the JavaScript code that would have specified what should be done when the entry in an input element changes.

  • Invoking vs Referencing Event Handlers: If you are relatively new to building React web apps, you may not realize that passing in the name of the event handling function with a pair of parentheses () will actually cause the function to execute when the component mounts/loads. But it does. So, when you pass in the event handler, make sure it is NOT invoked; make sure that it IS referenced instead.

  • Not Binding the Form's Input to the Component's Local State: In our `NewUser` component, we made sure that every input element on the registration form is bound to a piece of the component's local state. This we accomplished by using the `value` property on the input element. Failure to do this will mean that the related piece of the component's state will not be set to the value of what the user enters in the form.

 

So, make sure that every input element is bound to a piece of the component's local state by using the `value` property on the input element and passing it the name of the related component state enclosed in a pair of curly {} braces, like this:


<input 
    type='text'
    placeholder='First Name'
    style={{ marginLeft: '15px'}}
    value = {firstName}
    onChange = {(e) => setFirstName(e.target.value)}
/>

There may likely be other "gotchas" when it comes to doing form processing in your React components, but these are some of the most obvious ones.

 

If, while building your React components, you come across some strange errors or warnings or your component fails to load properly, fully or at all in your browser, use the `console.log()` to see if your form input, your component's local state and the expected result match up. If they don't, debug until you fix it.

 

Then, document what happened and how you got it fixed. This way, the next time you come across the same issue, you would already have a documented way of solving it.



7: Best Practices for Handling Form Processing in Your React Components

Of course, the inverse of the above gotchas are the best practices to be cognizant of when coding forms, handling form events and processing form submissions in your React app's components.

 

In addition to these, as you develop forms and handle form events in your React components, you should also:

 

  • Have a Form "submit" Event Handler: This should, ideally, be in an external function. Within the body of this event handler is where you check and validate the entry for all the form fields' data. If the form data is valid, proceed to submit the form. Otherwise, print an error message in the DOM so that the user can try to correct his/her entry before submitting the form.

  • Validate Form Data in the Backend: If your React component requires that the form data be sent to a backend API server, make sure that you also run the form data through your validation checks (in the backend) before you save the form data. Don't make yourself a victim of SQL injections, CORS issues or make yourself a victim of malicious intent by web criminals.

  • Decide on What to Do UX-wise After Form Submissions: Depending on the needs of your app, you may have to print confirmation messages, render error messages or redirect the user to a "success" page so they can start using your web app's features unhindered and unhinged.

 

Depending on the use case of your web app and the technical needs of our application, you may have to incorporate these into your code. Whatever approaches you decide to go with, just make sure you implement this logically and beautifully in your code.

 

There are other best practices, but consistent practice (and not just "listicles" of principles and "accepted" practices) is what you need to be a beter Frontend Developer.

 

So, to speak practically, just build more React apps with varying degrees of complexity, beauty and user experience and you will garner more best practices this way.



8: Technical Reference