This content originally appeared on DEV Community and was authored by william-luck
Component hierarchy:
Parent Component: App.js
... Child component: ExampleForm.js
... Child component: SubmittedFormInfo.js
Goal
I have an example form in the child component ExampleForm
to receive input on a name, image url, and a price for a new item. I want this information to immediately be displayed in another child component SubmittedFormInfo
, without the need to refresh the page.
Both of these components are children of App
, but information cannot be directly passed between sibling components such as these. How can we take the information from the form, and then immediately display that information in the other component?
Walkthrough
This issue depends on the use of state and setter functions passed down as props to each of the components. Since information cannot be directly passed between sibling components, we need to make use of state in the parent component, which will pass down information to each of the two components so that the data can be displayed.
App component
Begin by utilizing the useState hook in the App
component, and use an initial value of an empty object, which will eventually contain the information from our example form:
function App() {
const [newItem, setNewItem] = useState({})
We are not too concerned with the actual value of newItem
just yet. Instead, begin by passing down the setter function setNewItem
to the ExampleForm
component. The first goal here is that we want to change the value of newItem
upon form submission using the setter function passed down:
<ExampleForm setNewItem={setNewItem}/>
function ExampleForm({ setNewItem }) {
ExampleForm component
Before going further, we need to use a controlled form to keep track of the data submitted by the user. For simplicity, declare three initial values as empty strings for each input field on the form using the useState hook:
function ExampleForm({ setNewItem }) {
const [name, setName] = useState('')
const [image, setImage] = useState('')
const [price, setPrice] = useState('')
These will be used as values for each input in the example form, as follows:
<form>
<input type="text" name="name" placeholder="Name" value={name} />
<input type="text" name="image" placeholder="Image URL" value={image} />
<input type="number" name="price" placeholder="Price" value={price} />
<button type="submit">Add Item</button>
</form>
For controlled forms, every change that the user makes to the input field should update state to keep track on the information entered by the user. This is especially useful for immediately making use of the information, such as when you want matching items to display in the DOM using a search bar as the user types. Even though we only need this information upon submission, it is still helpful to use a controlled form. To make this form controlled, begin by declaring three separate functions to handle a change to each of the input fields. Within each function, we want to make use of the setName
, setImage
, and setPrice
setter functions from the state in this component. Each function should update state using the event object, to access data on each letter entered to the form:
function handleNameChange(event) {
setName(event.target.value)
}
function handleImageChange(event) {
setImage(event.target.value)
}
function handlePriceChange(event) {
setPrice(event.target.value)
}
To call these functions when the user inputs data, use these functions as callbacks for onChange events in each of the form input fields:
<form>
<input type="text" name="name" placeholder="Name" value={name} onChange={handleNameChange}/>
<input type="text" name="image" placeholder="Image URL" value={image} onChange={handleImageChange}/>
<input type="number" name="price" placeholder="Price" value={price} onChange={handlePriceChange}/>
<button type="submit">Add Item</button></form>
The general idea is that as the user types, each of these functions will be called to update state. Since we are using state variables as the input values in the form, the form values will update as the state updates with the use of the handle functions. Once the user finishes typing, we will have complete information available to use in each of the name
, image
, and price
state variables.
When the user submits the form, we want to change the value of newItem declared in App
, using the information entered by the user. We can do this by calling the setter function setNewItem
, which was passed down as a prop to the form component. Begin by declaring a handleSubmit function, which should be called when the user submits the form using onSubmit in the opening form tag. In the handleSubmit function, we want to create a new object, specifying key/value pairs using state variables as each value, as so:
const formData = {
name: name,
image: image,
price: parseInt(price)
}
Then call setNewItem
, using the formData object as the specified value:
setNewItem(formData)
Optionally, we can prevent a refresh of the page and set the form values back to empty strings to receive new data from the user. The final handleSubmit function should look something similar to this:
function handleSubmit(event) {
event.preventDefault();
const formData = {
name: name,
image: image,
price: parseInt(price)
}
setNewItem(formData)
setName('')
setImage('')
setPrice('')
}
The primary line of code to focus on here is setNewItem(formData)
. This updates state in the parent App
component, which allows us to then pass that form data to SubmittedFormInfo
as a child of App
.
SubmittedFormInfo component
To finally display the form data in our application, in the App
component, pass down newItem
as a prop to SubmittedFormInfo
:
<SubmittedFormInfo newItem={newItem}/>
newItem
now contains an object with the name, image url, and price of the item added by the user. Have SubmittedFormInfo
receive the prop, and optionally destructure newItem to more easily use the information contained in the newItem object.
function SubmittedFormInfo({ newItem }) {
const {name, image, price} = newItem
All that is left to do is display the name, image, and price variables in the DOM:
return (
<header>
<h2>
Submitted Form Data
</h2>
<p>Name: {name}</p>
<p>Image url: {image}</p>
<p> Price: ${price}</p>
</header>
);
}
With this addition, once the user submits the form, the information entered by the user should now display automatically in the DOM. This occurs because of state updates. Since SubmittedFormInfo
depends on the variable newItem
in state, once the value of newItem
updates, this will cause the SubmittedFormInfo
component to re-render, immediately displaying the information entered by the user.
Conclusion
We used newItem
and its setter function to update the application. We began by passing down 'setNewItem' to ExampleForm
, which was called when the user submitted the form. As the user typed, state in the form component updated, keeping track of the values entered by the user. Upon submission, we set the value of newItem
to the data entered by the user. This caused a state update for newItem
, which was passed down to our display container as a prop. This component then re-rendered upon submission, displaying the information entered by the user immediately below the form, with no need to refresh the page.
This content originally appeared on DEV Community and was authored by william-luck
william-luck | Sciencx (2022-07-18T23:06:29+00:00) Tutorial: communication between sibling components using state, and controlled forms. Retrieved from https://www.scien.cx/2022/07/18/tutorial-communication-between-sibling-components-using-state-and-controlled-forms/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.