FullStack Labs

Please Upgrade Your Browser.

Unfortunately, Internet Explorer is an outdated browser and we do not currently support it. To have the best browsing experience, please upgrade to Microsoft Edge, Google Chrome or Safari.
Upgrade
Welcome to FullStack Labs. We use cookies to enable better features on our website. Cookies help us tailor content to your interests and locations and provide many other benefits of the site. For more information, please see our Cookies Policy and Privacy Policy.

Angular to React.js - Forms (Part 5 of 6)

Written by 
,
Angular to React.js - Forms (Part 5 of 6)
blog post background
Recent Posts
Six Ways to Handle Concurrency in the JVM
Is there value in learning Vanilla JavaScript?
How to be efficient in remote design work in multicultural teams

Welcome back to the fifth part of my six-part guide for Angular developers looking to learn React. At this point, our app allows users to view a product catalog, click a product name, navigate to a product’s detail page, add the product to a cart, and view the cart. Our next step is to collect information from users so they can purchase products from our store.

Table of contents

To get started, fork the project

Creating Forms in React

React on its own does not include specific functionality for managing forms. Form elements need to be managed using javascript without a framework, also known as Vanilla javascript.

Let’s start by looking at an input element.

-- CODE language-jsx keep-markup --
<input type="text" value="{name}" onchange="{(e)" ==""> handleChange(e, setName)} />

We need to find a way to manually update the prop value whenever the onChange event is called.

To control the value props, we will create a local state and function.

-- CODE language-jsx keep-markup --
const ReactForm = () => {  
  const [name, setName] = useState("");  
  const handleChange = event => {      
    setName(event.target.value);  
  };  
  return<input type="text" value="{name}" onchange="{handleChange}">
}

React requires a separate state for each input element and a handleChange method to update the value prop. Our simple example above only handles one input element, but real-world forms can contain many input elements. Manually implementing a large form with many inputs can be tedious without the help of React libraries created specifically for form management.

For this project, we will use one of the most popular React form libraries, Formik. To learn more about some of the other popular libraries, take a look at this article.

Setting Up Formik

  • Following the instructions in the Formik documentation, add Formik to the project.
  • Create UserInformation.js inside the Components folder.
  • Copy and paste the code below into the file you just created.

-- CODE language-jsx keep-markup --
import React from "react";
import { Formik } from "formik";
import * as Yup from "yup";  

const UserSchema = Yup.object().shape({  
  name: Yup.string().required("Name is required"),  
  address: Yup.string().required("Address is required")
});  

const UserInformation = ({ clearCart }) => (  
  
    initialValues={{ name: "", address: "" }}    
    validationSchema={UserSchema}    
    onSubmit={(values, { setSubmitting, resetForm }) => {      
      setTimeout(() => {        
        console.warn(          
          "Your order has been submitted",          
          JSON.stringify(values, null, 2)        
        );        
        setSubmitting(false);        
        clearCart();        
        resetForm();    
      }, 400);    
    }}  
  >    
    {({      
      values,      
      errors,      
      touched,      
      handleChange,      
      handleBlur,      
      handleSubmit,      
      isSubmitting    
    }) => (      
      <form onsubmit="{handleSubmit}"></form>
        <div></div>
          <label htmlfor="name">Name</label>
          
            type="text"            
            name="name"            
            onChange={handleChange}            
            onBlur={handleBlur}            
            value={values.name}          
           />          
           {errors.name && touched.name &&<p classname="error">{errors.name}</p>}        
        
        <div></div>
          <label htmlfor="address">Address</label>
          
            type="text"            
            name="address"            
            onChange={handleChange}            
            onBlur={handleBlur}            
            value={values.address}          
           />          
           {errors.address && touched.address &&<p classname="error">{errors.address}</p>}        
         

         <button type="submit" disabled="{isSubmitting}">          </button>
           Purchase        
         
           
     )}
  
);  
export default UserInformation;

  • Import the UserInformation component into the Cart.js component, and insert the new UserInformation component below the products list.

-- CODE language-jsx keep-markup --
import UserInformation from './UserInformation';
  
  ...
  {products.map(item => (  
    <div key="{item.name}" classname="cart-item"></div>
      <span>{item.name}</span>
      <span>{utils.currency(item.price)}</span>
    
))}
<userinformation clearcart="{clearCart}"></userinformation>
...

Your cart now includes a form with name and address fields.

Managing Forms with Formik

When we created the UserInformation file above, we wrapped the HTML form element in a function instead of providing it directly as a child of the Formik component. This is called a renderprops pattern. This pattern allows Formik to provide a set of methods and variables to the HTML form elements - like handleChange and handleBlur - that make form management more efficient.

-- CODE language-jsx keep-markup --

...
>
  {formStatesAndSharedMethods => (    
    {/* You can access the shared functionality here */}  
  )}


To control the HTML form submit event, we will use the handleSubmit function.

-- CODE language-jsx keep-markup --
<form onsubmit="{handleSubmit}"></form>

To manage the HTML input elements we will use handleChange, handleBlur, and the values object.

-- CODE language-jsx keep-markup --

  type="name"  
  name="name"  
  onChange={handleChange}  
  onBlur={handleBlur}  
  value={values.name}
/>

To control form errors, we will use Formik’s errors object. For example, errors.address will display the errors of the form element with the name address.

If a user has not yet touched an input, we don’t want the error to display. Luckily, we can access the touched object to identify user interaction.

-- CODE language-jsx keep-markup --
{errors.address && touched.address &&<p classname="error">errors.address</p>}

Our form should be disabled after a user clicks the submit button to prevent the system from sending multiple requests to the server before it can respond. To disable the button after the first submission, we can add the isSubmitting variable to the disabled prop.

-- CODE language-jsx keep-markup --
<button type="submit" disabled="{isSubmitting}"></button>

For a list of all available Formik methods and variables, visit here.

Improving the Code

Formik provides Form, Field and ErrorMessage components to make the current implementation more concise.

  1. Create a new component called UserInformationRefactor.js inside the /components folder.
  2. Copy and paste the following code:

-- CODE language-jsx keep-markup --
import React from "react";
import { Formik, Form, Field, ErrorMessage } from "formik";  

const UserInformation = ({ clearCart }) => (  
  
    initialValues={{ name: "", address: "" }}    
    onSubmit={(values, { setSubmitting, resetForm }) => {      
      setTimeout(() => {        
        console.warn(          
          "Your order has been submitted",          
          JSON.stringify(values, null, 2)        
        );        
        setSubmitting(false);        
        clearCart();        
        resetForm();      
      }, 400);    
    }}  
  >    
  {({ isSubmitting }) => (      
    <form></form>
      <div></div>
        <label htmlfor="name">Name</label>
        <field name="name"></field>
        <errormessage name="name" component="p"></errormessage>
      
      <div></div>
        <label htmlfor="address">Address</label>
        <field name="address"></field>
        <errormessage name="address" component="p"></errormessage>
      

      <button type="submit" disabled="{isSubmitting}">          </button>
        Purchase        
      
        )}
  
);

export default UserInformation;

The code above replaces the default HTML elements with corresponding Formik components: form becomes Form, input becomes Field, and errors are shown with ErrorMessage. These Formik components automatically handle much of the functionality we implemented manually.

The Form component sets up the onSubmit={handleSubmit} prop so you don’t have to provide it.

The Field component renders an <input> element with the onChange={handleChange}, onBlur={handleBlur}, and value={values[name]} props based on the name prop provided.

The ErrorMessage component conditionally renders the error associated with the corresponding Field component’s name.

Implementing Validation

Although we set up the form error display above, we have not yet configured the list of possible errors for each component.

  • Install the library yup.
  • Import the package.

-- CODE language-jsx keep-markup --
import * as Yup from "yup";

  • Create a Yup object with the following configuration:

-- CODE language-jsx keep-markup --
const UserSchema = Yup.object().shape({  
  name: Yup.string().required("Name is required"),  
  address: Yup.string().required("Address is required")
});

  • Add the prop below to the Formik component.

-- CODE language-jsx keep-markup --

  validationSchema={UserSchema}

  • Add the following styles into the style.css file.

-- CODE language-jsx keep-markup --
.error {  
  color: #FA4048;  
  margin: 0 0 16px;  
  font-size: 13px;
}

Now, the associated error will display if the field has been touched and the user clicks away.

To learn more about yup, browse the yup documentation.

Solutions

What's next?

So far, we have covered setup, routing, data management, async actions, and form management. The final article of this series will cover the deployment process. See you there.

---

At FullStack Labs, we pride ourselves on our ability to push the capabilities of cutting-edge frameworks like React. Interested in learning more about speeding up development time on your next project? Contact us.

Written by
People having a meeting on a glass room.
Join Our Team
We are looking for developers committed to writing the best code and deploying flawless apps in a small team setting.
view careers
Desktop screens shown as slices from a top angle.
Case Studies
It's not only about results, it's also about how we helped our clients get there and achieve their goals.
view case studies
Phone with an app screen on it.
Our Playbook
Our step-by-step process for designing, developing, and maintaining exceptional custom software solutions.
VIEW OUR playbook
FullStack Labs Icon

Let's Talk!

We’d love to learn more about your project.
Engagements start at $75,000.

company name
name
email
phone
Type of project
How did you hear about us?
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.