Creating custom Forms in React with stateless inputs
Tags: react, javascript, programming, webdev
Published: 2021-10-10 11:33:03

## Introduction
Ever seen something like this?
![stateful input elements](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ui51f3s9y3u1usj4h0nd.png)

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 🤯
![stateful tedious arrangement of elements](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m2ff5rcvuobhpn78w5kg.png)

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.
![children passed in parent element example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwm9uxlejn6ize2ciy9x.png)
 

If we `console.log` each child in the `Form` component, it looks something like this
![each child of the children prop passed into parent element](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ipz7eg3l3sd74b7zea7o.png)
 

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](https://stackoverflow.com/questions/42801343/what-is-the-significance-of-keys-in-reactjs). we'll be using the key just to indicate the fieldname here).
Also passing 2 extra props (`formData` & `setFormData`) in `Form` component

```javascript
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`

```javascript
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
![lovely professional input for output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fxce7b91pz4f7dlsf8bz.png)

![lovely professional output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf648g823rilgmjht81a.png)

**IT WORKS!**