Introduction
Ever seen something like this?

In this article, i will be trying to solve this problem. So lets get started!
Problem
Its a tedious task to make big forms with managed state of each of the input. Imagine a form with 10 more fields 🤯

What if we could contain the input elements in a parent element and manage their state within a single source of truth? That would be awesome right. Lets build the parent component!
Solution
Lets create a React Component & call it Form and pass the input elements as its children. To recall, we know that the children of a component could be accessed by the children prop of the component which is just an array of its children.

If we console.log each child in the Form component, it looks something like this

Now, we desire an output from the Form component in a Javascript Object in form of key-value pairs corresponding to fieldnames and their respective input values.
If we could alter the value prop and handle the onChange prop of the element, our mission will be accomplished!
But wait... how do we know while mapping, what fieldname we are on? and where & how to store the data of an input when it changes?
To resolve this problem, we'll give an additional prop to the child elements called key (another fancy default prop of a react element check its use here. we'll be using the key just to indicate the fieldname here).
Also passing 2 extra props (formData & setFormData) in Form component
import { useState } from "react";
import Form from "./Form";
import "./styles.css";
export default function App() {
  const [formData, setFormData] = useState(null)
  return (
    <div className="App">
      <Form setFormData={setFormData} formData={formData}>
        <input key='name' placeholder='Enter name' />
        <input key='email' placeholder='Enter email' />
        <input key='phoneNumber' placeholder='Enter phone' />
        <input key='address' placeholder='Enter address' />
      </Form>
      <button onClick={() => console.log(formData)}>Submit</button>
    </div>
  );
}
In the Form component, we create a new array by mapping the children array and altering the props field.
value of the element is taken from formData variable and onChange function is mapped to another function which changes the field's value by using the key (being accessed by child.key) and stores in the formData via setFormData
export default function Form({ children, formData, setFormData }) {
  const handleInputChange = (key, text) => {
    let newFormData = { ...formData }
    newFormData[key] = text
    setFormData(newFormData)
  }
  const mappedChildren = children.map(child => {
    return {
      ...child,
      props: {
        ...child.props,
        onChange: e => handleInputChange(child.key, e.target.value),
        value: formData ? formData[child.key] : ''
      }
    }
  })
  return (
    <section>
      {mappedChildren}
    </section>
  )
}
The component is complete, lets check its working by logging formData on the console

IT WORKS!

    
Top comments (0)