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)