Written by: Geoffrey Callaghan

Forms In React

Forms In React

Forms in React are used to capture user input and handle it effectively within the application. React provides a way to manage form elements such as input, select, and textarea through controlled components, which means that form data is handled by the state in React. Here’s a comprehensive guide to understanding and working with forms in React:

Controlled Components

In a controlled component, form data is handled by the component’s state. The state is the single source of truth, and the input elements get their values from the state and update the state on every change.

Example of a Controlled Component:

import React, { useState } from 'react';

function ControlledForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({
      ...formData,
      [name]: value
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form data submitted:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" name="name" value={formData.name} onChange={handleChange} />
      </label>
      <br />
      <label>
        Email:
        <input type="email" name="email" value={formData.email} onChange={handleChange} />
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default ControlledForm;

Uncontrolled Components

Uncontrolled components allow the form data to be handled by the DOM itself. React provides a way to access form values using refs.

Example of an Uncontrolled Component:

import React, { useRef } from 'react';

function UncontrolledForm() {
  const nameRef = useRef();
  const emailRef = useRef();

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form data submitted:', {
      name: nameRef.current.value,
      email: emailRef.current.value
    });
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        <input type="text" ref={nameRef} />
      </label>
      <br />
      <label>
        Email:
        <input type="email" ref={emailRef} />
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default UncontrolledForm;

Handling Multiple Inputs

When handling multiple inputs, it is common to use a single change handler and update the state accordingly.

Example:

import React, { useState } from 'react';

function MultipleInputsForm() {
  const [formData, setFormData] = useState({
    firstName: '',
    lastName: '',
    email: ''
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({
      ...formData,
      [name]: value
    });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form data submitted:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        First Name:
        <input type="text" name="firstName" value={formData.firstName} onChange={handleChange} />
      </label>
      <br />
      <label>
        Last Name:
        <input type="text" name="lastName" value={formData.lastName} onChange={handleChange} />
      </label>
      <br />
      <label>
        Email:
        <input type="email" name="email" value={formData.email} onChange={handleChange} />
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default MultipleInputsForm;

Form Validation

React does not provide built-in form validation, but you can easily implement it using state and conditional rendering.

Example with Simple Validation:

import React, { useState } from 'react';

function ValidatedForm() {
  const [formData, setFormData] = useState({
    email: '',
    password: ''
  });

  const [errors, setErrors] = useState({
    email: '',
    password: ''
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData({
      ...formData,
      [name]: value
    });

    setErrors({
      ...errors,
      [name]: ''
    });
  };

  const validate = () => {
    const newErrors = {};
    if (!formData.email.includes('@')) {
      newErrors.email = 'Invalid email address';
    }
    if (formData.password.length < 6) {
      newErrors.password = 'Password must be at least 6 characters';
    }
    return newErrors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validate();
    if (Object.keys(validationErrors).length > 0) {
      setErrors(validationErrors);
    } else {
      console.log('Form data submitted:', formData);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Email:
        <input type="email" name="email" value={formData.email} onChange={handleChange} />
        {errors.email && <span>{errors.email}</span>}
      </label>
      <br />
      <label>
        Password:
        <input type="password" name="password" value={formData.password} onChange={handleChange} />
        {errors.password && <span>{errors.password}</span>}
      </label>
      <br />
      <button type="submit">Submit</button>
    </form>
  );
}

export default ValidatedForm;

Third-Party Libraries

For more complex form handling, you might want to use a third-party library such as Formik or React Hook Form. These libraries provide additional functionality and ease the process of form management, validation, and error handling.

Example using Formik:

import React from 'react';
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';

const SignupSchema = Yup.object().shape({
  email: Yup.string().email('Invalid email').required('Required'),
  password: Yup.string().min(6, 'Too Short!').required('Required')
});

function FormikForm() {
  return (
    <div>
      <h1>Signup</h1>
      <Formik
        initialValues={{ email: '', password: '' }}
        validationSchema={SignupSchema}
        onSubmit={(values) => {
          console.log('Form data submitted:', values);
        }}
      >
        {({ isSubmitting }) => (
          <Form>
            <label>
              Email:
              <Field type="email" name="email" />
              <ErrorMessage name="email" component="div" />
            </label>
            <br />
            <label>
              Password:
              <Field type="password" name="password" />
              <ErrorMessage name="password" component="div" />
            </label>
            <br />
            <button type="submit" disabled={isSubmitting}>Submit</button>
          </Form>
        )}
      </Formik>
    </div>
  );
}

export default FormikForm;

Summary

  • Controlled Components: Form data is controlled by React state.
  • Uncontrolled Components: Form data is controlled by the DOM using refs.
  • Handling Multiple Inputs: Use a single change handler to manage multiple form inputs.
  • Form Validation: Implement validation manually or using libraries like Yup.
  • Third-Party Libraries: Use libraries like Formik or React Hook Form for advanced form handling and validation.

Using these techniques, you can effectively manage forms in React applications.