React enables developers to write reusable code in the form of components. This modular approach makes it simple to develop robust apps by following a parent-child structure and adding those components in as many times as needed. To configure a component, you can use props (data you pass to the component) whereas state allows you to manage the data that may change inside of that specific component. In other words, with state you can control how it behaves and renders. This guide will demonstrate how to make a parent component aware of actions or changes in the child by passing state as props. Although we will use functional components, the same applies to class-based ones.
To illustrate, we will store an array of basketball players as objects in the state of the main app component. Next, we will pass that piece of state to a child (Player
) component for visualization purposes. Finally, we will set up a function to remove players one by one and see how that impacts the state of the parent. The final code—including all the files—is available in Codesandbox and GitHub.
To begin, create the following App.js file:
1import React, { useState } from "react";
2import Player from "./components/Player/Player";
3import "./styles.css";
4
5export default function App() {
6 const [players, setPlayers] = useState([
7 {
8 name: "LaMarcus Aldridge",
9 yearsPro: 14,
10 position: "Center-Forward"
11 },
12 {
13 name: "Marco Belinelli",
14 yearsPro: 13,
15 position: "Guard"
16 },
17 {
18 name: "DeMar DeRozan",
19 yearsPro: 11,
20 position: "Guard-Forward"
21 }
22 ]);
23
24 const playersList = players.map(({ name, yearsPro, position }) => (
25 <li key={name.replace(" ", "").toLowerCase()}>
26 <Player
27 allPlayers={players}
28 removePlayer={setPlayers}
29 name={name}
30 yearsPro={yearsPro}
31 position={position}
32 />
33 </li>
34 ));
35
36 return (
37 <div className="App">
38 <h1>Team Members ({players.length})</h1>
39 <ul className="List">{playersList}</ul>
40 </div>
41 );
42}
Now, examine what you have so far step by step.
1import React, { useState } from "react";
2import Player from "./components/Player/Player";
3import "./styles.css";
React (as expected) and the useState
hook. The latter will allow you to access and manipulate the state of the current component.
A Player
component (which you will add later)
2) A list of basketball players. Through useState
, you initialize a piece of state in a variable named players
and a function (setPlayers
) to update it later
1const [players, setPlayers] = useState([
2 {
3 name: "LaMarcus Aldridge",
4 yearsPro: 14,
5 position: "Center-Forward"
6 },
7 {
8 name: "Marco Belinelli",
9 yearsPro: 13,
10 position: "Guard"
11 },
12 {
13 name: "DeMar DeRozan",
14 yearsPro: 11,
15 position: "Guard-Forward"
16 }
17]);
3) An array that consists of a series of children components. Here you will be passing the state (the players
variable and the setPlayers
function) as props to each instance of Player
. This will allow you to manipulate the parent's state from each child.
1 const playersList = players.map(({ name, yearsPro, position }) => (
2 <li key={name.replace(" ", "").toLowerCase()}>
3 <Player
4 allPlayers={players}
5 removePlayer={setPlayers}
6 name={name}
7 yearsPro={yearsPro}
8 position={position}
9 />
10 </li>
11 ));
4) The return
statement that will display the number and list of players (which you will modify via the state):
1return (
2 <div className="App">
3 <h1>Team Members ({players.length})</h1>
4 <ul className="List">{playersList}</ul>
5 </div>
6);
Once you put the child component in place in the next section, you will observe how the number of players (players.length
) and therefore the list itself (playersList
) are impacted by actions that occur in it.
The Player
component consists of a span
element that displays the player's name, position, and years of experience. In addition, the handleRemove
function will make it possible to remove each player from the parent's state when you click on the corresponding item in the list. To accomplish this, insert the following lines in a file called Player.js
:
1import React from "react";
2import "./Player.css";
3
4// Destructuring props in the function arguments.
5const Player = ({ allPlayers, name, yearsPro, position, removePlayer }) => {
6 const handleRemove = () => {
7 const filteredPlayers = allPlayers.filter((player) => player.name !== name);
8 removePlayer(filteredPlayers);
9 };
10
11 return (
12 <span onClick={handleRemove}>
13 {name} ({position}) | Years pro: {yearsPro}
14 </span>
15 );
16};
17
18export default Player;
At this point, you should see the following in the browser:
Next up, see what happens when the handleRemove
function is triggered in a given Player
component.
Now that you have set up the state in the parent and passed it to the child as props, click on any of the players and see how it is removed from the list:
As you can see, the number of players is now two. If you click on another player, it will decrease to one:
Thus, you can confirm that the actual list of players (which resides in App.js
) is modified when you manipulate the props in Player
.
Alternatively, you can inspect the components using the React Developer Tools:
First, click on App and observe its state under the Hooks section on the right pane. Second, click on a given player component and examine its props. Finally, click on any of the items in the page and see how the state and props of the parent and child components are updated, respectively.
While the example in this guide is rather simple, you will find this same principle in all kinds of React-based apps. For example, you can think of a shopping cart with the total price as the parent component and each purchased item with its corresponding subtotal and individual quantity as a child.
Passing state as props from parent to child components is a core concept of React. By keeping state in only a few components and passing it to as many children as needed in the form of props, you will be able to write code that is easier to maintain, and you will thank yourself down the road.