Section 1
Practicing State & Props

Passing Props
Learning Objectives
- Create and pass props to Components
- Loop over an array of data and pass multiple props
- Work with additional JSX rules.
- Explain what
state
is and how to implement it in React - Use
Array Destructuring
to create variables from an array - Update
state
and re-render the Component
Framing
Having worked with functions we know that they are meant to be reusable. Part of the reusability is in accepting arguments, performing an action and returning a value.
Standard Input
produces Standard Output
Now consider that our application contains many Components, some of which may require data points in order to render the UI.
The data we pass from a parent > child Component
are called: props
. Make note that it is the parent that passes props to a child.
React data flow is unidirectional
and can only be passed down, and never directly from child
to parent
or sibling
to sibling
.
Props
Every Component has props
and that is how data is passed from a parent to a child Component.
⏰ Activity - 3min
Let's all fork this code sandbox as our starter code in
React Developer Tools
see if anything props
related pops out.
If we highlight the Card1
Component we will see something called props
to the right.
Since we haven't yet passed any data to these Components there is nothing to show.
End Goal
Once we have implemented all the steps in today's lecture on props
React Dev Tools will look more like:

Here is a live version of today's solution.
Prop Rules
Let's extend the rules for creating Components and working with JSX to now include props
.
🚔 Props adhere to the following rules:
- Data is unidirectional passed down from a
parent
>child
- All Props passed to a child are organized into a single object in the child Component
- Props are
immutable
and cannot be reassigned a new value within the receiving child Component
This Rule isn't regarding props but something we will need to keep in mind going forward:
- Any Components created using Array.map() must be assigned a key prop with a unique value.
Passing Props
Say for instance we wanted to render the name that the image represents in our cards example. We could go directly to CardBody
and do the following:
<h5 className="card-title">Santorini</h5>
This is a fairly manual process and wouldn't be efficient if we had 100 or 1000 cards to render.
So let's add a prop
to CardBody and pass it the value of Santorini
.
A prop
is written in a name=value
format like the other html attributes your used to writing such as:
<!-- The src property of a image tag -->
<img src="someurl" />
<!-- The class property assigned to any element -->
<div className="container"></div>
<!-- The href property assigned to an anchor tag -->
<a href="someurl"></a>
Since the Card1
component is the parent that renders CardBody
than it must pass the prop to it's child.
🚔 - Data is unidirectional in React and is passed down from a parent
> child
Component
Let's assign CardBody the following prop
.
<CardBody title="Santorini"/>
Nothing should really change as we have already updated CardBody with that title name. So we need to update the CardBody Component to accept props.
Accepting Props
The first thing we need to do is add the keyword props
as a parameter. So inside CardBody.js make the following change.
Let's make sure that our Component is being passed the title
prop by adding a console.log.
export default function CardBody(props) {
console.log('this is props:', props)
// ...rest of the code
}
In DevTools you should see the following in the console.

We can see here that props
is an object and that title
is a key. This will be the same pattern for when we start passing in multiple props. Each prop passed will be assigned a key:value pair.
:alarm_clock: Activity - 3min
Let's take a moment to edit our code and try to reassign props.
- Open the
CardBody
Component and add the following:
console.log('current props.title', props.title);
// ATTEMPT TO REASSIGN PROPS A NEW VALUE
props.title = 'Mykonos';
console.log('props.title', props.title);
Refresh the page and you should see the following:

So it looks like props was not updated to reflect the edit. This is an example of one of the rules of props:
🚔 - Props are immutable which means you can't reassign them within the receiving Component
So any attempt to change those props directly within the Component will have no effect.
Using Props
Now that we have confirmed we are being passed the value we need for title let's use it to replace the hard coded value.
Let's try and use the prop that was passed.
<h5 className="card-title">props.title</h5>
the result should be...

That didn't seem to work out as planned. It seems it outputs props.title
and not the value
props.title
It seems we forgot about one of the rules of JSX:
🚔 Any JavaScript code that needs to be executed in JSX must be enclosed in opening/closing curls braces {}
(Remember, think of {}
in React like the <% %>
in ejs)
<h5 className="card-title">{props.title}</h5>
⏰ Activity - 1min
Confirm in React Dev Tools that CardBody is now being passed a prop
:thumbsup: Click on the thumbs up when your done.
Passing Mulitple Props
We could do the same for all the additional values we wish to pass but as you can imagine if we had 10, 20, 100+ cards this manual method becomes completely inefficient.
Also it is more likely that the data we will be using to render the cards will be imported either via a file or returned from an API call.
Either way we should expect that if we will need to create multiple cards that the data will be stored as an array of objects: [{}, {}]
⏰ Activity - 3min
Let's use some real data and replace the generic placeholder text.
- Create a new file in
src
calleddata.js
- paste the following code into the file
export default [
{
img: "https://images.unsplash.com/photo-1536514072410-5019a3c69182?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=60",
title: "Santorini",
text: "This was one of the most amazing places I've ever seen. A must see for eveyrone",
url: "https://unsplash.com/s/photos/santorini"
},
{
img: "https://images.unsplash.com/photo-1498712964741-5d33ab9e5017?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&q=600",
title: "Zakynthos",
text: "This was like being a pirate and we were looking to bury our treasure. It was so isolated and beautiful. ",
url: "https://unsplash.com/s/photos/santorini"
}
]
- Import the data into
App.js
ascardsArr
and add a console.log to confirm it was imported.
// IMPORT DATA
import cardsArr from './data'
console.log('this is cardsArr:', cardsArr)
:thumbsup: Click on the thumbs up when your done.
Creating Multiple Cards
With the data in hand we can now loop over the array and render as many Card Components
as we need and pass them the props needed for each card.
Inside of the App
Component we will loop over the cardsArr
array and create multiple Cards in one shot.
Each prop is defined on it's own and passed it's corresponding value.
Let's also console the cards
so see what React magic has been performed.
const cards = cardsArr.map((ele, index) => {
return (
<Card1
img={ele.img}
title={ele.title}
text={ele.text}
url={ele.url}
/>
);
})
console.log('this is cards:', cards);
Now take a look in DevTools and you should see the following:

Each object appears to contain much more info then we passed and each one has a typeof
set to Symbol(react.element)
. Symbols
were a new data type introduced in ES6 and are meant to be unique, meaning there will not be Symbol
in this array with the same exact info.
Something will be needed to distinguish it as unique. React does so by assigning a key called key
.
It is currently set to null
and React will warn in just a bit when we render the Cards based on the following rule:
🚔 Any Components created within a .map() must be assigned a unique key.
Before we render the Cards we first need to update Card1
to pass the data down the props it's received to it's corresponding children.
export default function Card1(props) { {
console.log('this is props:', props)
return (
<div className="card" style={{width:'18rem'}}>
<CardImage img={props.img} />
<CardBody title={props.title} text={props.text} url={props.url} />
</div>
)
}
CardBody
Let's update CardBody
to make use of the props.
export default function CardBody(props) { {
return (
<div className="card-body">
<h5 className="card-title">{props.title}</h5>
<p className="card-text">{props.text}</p>
<Button url={props.url}/>
</div>
)
}
⏰ Activity - 10min
Now it's your turn.
Take a moment to update the following Components to accept and use props:
- CardImage
- Button
Keep in the mind the following:
- Both Components need to include a parameter which we will always call
props
. - Any JS rendered in JSX must be wrapped in {}
:thumbsup: Click on the thumbs up when your done.
Reusable Components
Now it's time to see all that code refactoring done to Card1
in action.
In App comment out <Card1 />
and <Card2 />
. We will now replace those values with the data returned via the .map() and stored in cards
.
<section className="cards">
{cards}
{/* <Card1 title="Santorini" />
<Card2 /> */}
</section>
The Key Prop
As you may recall it was mentioned earlier that the elements would render fine however React would present an error. The following error to be exact:

This can easily be fixed by assigning a key
prop to each element with a unique value. Since each element in an array is assigned a unique index value we will opt to use that.
const cards = cardsArr.map((ele, index) => {
return (
<Card1
img={ele.img}
title={ele.title}
text={ele.text}
url={ele.url}
key={index}
/>
);
})
Since the goal of a Component is to be reusable we could now use Card1 as our base template for rendering as many cards as we need.
It makes more sense to rename Card1.js
to Card.js
and update both the import statement and the Component name in the map.
Below includes those 2 updates(note this an old screenshot from my last class, so it looks slightly diff).

And there you have it. Multiple Components rendered via a loop with each being the props they need to render appropriately.
Final React Architecture
As we have made some design changes let's take a look at our final React Architecture design that takes into account all Components and the props being passed.

The above was created using Google Draw
The architecture represents all the Components and the props that are being passed to each one. This makes it much easier to understand the flow of data in our app.
Bonus - The ...spread Operator and Object Destructuring
Since passing props is a requirement in React there are a few shortcuts we can make when passing them.
Using The ...spread Operator
The first is that we can use the ...spread
operator to pass many key:value's down instead of writing them out one at a time.
In Card.js
let's replace all those hard coded props, except key
, with the ...spread
operator.
const cards = cardsArr.map((ele, index) => {
return (
<Card1
{...ele}
key={index}
/>
);
})
Using Object Destructuring
The other shorthand we can use is to update the Child components to create variables based on the key:value pairs that are in the props
object.
CardBody
Let's update CardBody
to make use of Object Destructuring. Here we use an object as parameter that includes all the prop key names that are being passed down.
export default function CardBody({title, text, url}) {
return (
<div className="card-body">
<h5 className="card-title">{title}</h5>
<p className="card-text">{text}</p>
<Button url={url}/>
</div>
)
}
⏰ Activity - 2min
Take a moment to update the CardImage
and Button
Component to make use of Object Destructuring.
:thumbsup: Click on the thumbs up when your done.
Final Solution
Here is the Final Solution
New App
Framing
The best analogy to understand React state
is to start by answering the following question: How are you feeling this very moment?
- Are you happy to be in class learning a new topic?
- Are you frustrated having to sit in class for the next several hours learning even more React?
- Did some random person say
hello
out of the blue make you smile?
The answer to any one of those questions has a direct impact on your state
of mind. A happy
state will be reflected in your smile, tone of voice, being nice to others in return. An unhappy
state will have the opposite effect.
As with all human beings our state
of mind can change on the fly which is almost always reflected in our facial expressions or actions. Applications also have a state
which is reflected in the UI presented to the user.
Therefore updating an applications state
is our control mechanism for how we update the UI.
Props Recap
So far we've worked with props
and used them to pass values from a parent
to a child
Component. This pattern of passing data down will be consistent in React as the flow of data is unidirectional
and always flows down.
We also know that the props passed down to a child are organized, by React, into an object where every prop becomes a key:value
pair.
Props are a great way to pass data but have the following limitations:
- Data in React is unidirectional and props are always passed down from parent > child
- Props are immutable
- Reassigning a prop value will have no effect on the Component.
- Child Components cannot communicate directly and therefore cannot pass data between them
:mag: Check for Understanding
-
Take a a minute to think about the following questions:
- What do we use
props
for? - What limitations do
props
have? - Is there any best practice you can think of when creating a
prop
?
- What do we use
:thumbsup: Click on the thumbs up when your done.
When asked slack your answer(s) in a thread created by the instructor
Intro To State
In our attempt to provide a coherent framing of React state
the point was made that what you see on the page is the current version of the applications state
. Any changes to state
will then be reflected in the UI.
One important thing to note here is that any changes to state will cause the Component to re-render
.This is essentially how the UI is updated.
This is a very important concept to keep in mind as a re-render
can also initiate additional function calls, something we will discuss as part of Reacts lifecycle methods
.
Rules Of State
:oncomingpolicecar: - Here are the rules we need to follow when working with state.
- State is assigned using the
useState
oruseReducer
hook - The State value can be assigned any data type
- The State value is never updated directly but only using its corresponding
setState
function - The state value must always be overwritten with a new value
Working With State
So updating state will, most often, require the user to interact with the application. Hence, the user performs some action, like clicking a button, and the component responds by doing a thing
and then updating state
.
Now it's time to dive in and build a small Counter app that contains state.
A Simple Counter Component (Remind you of what we did before??? Remember spaced repetition)
We'll walk through building a very simple Counter
Component which will do the following:
- provide the user 2 buttons to increment or decrement
- display the initial and update value as it changes
Spin Up A New CodeSandbox
For this demo you will spin up a new CodeSandbox. To do this just click on the blue Create Sandbox
button on the right of the page.

Now scroll down to the Official Templates
section and choose React by CodeSandbox
.
:thumbsup: Click on the thumbs up when your done.
Creating The Counter Component
⏰ Activity - 3min
Since you already have experience creating Components take a minute to perform the following activity.
Counter Component
- Create a new file in
src
calledCounter.js
- Import
React
- Create the Component
- Return the following HTML:
<>
<span>Current Count: 0</span>
<section>
<button>+</button>
<button>-</button>
</section>
</>
- Export the Component
App Component
- Import the Component into
App.js
- Replace all the html inside of
className="App"
with theCounter
Component.
<div className='App'>
<Counter />
</div>
Once your done React should render the following:

That HTML looks like it could use a little styling. So lets copy/paste the following css to styles.css
CSS
.App {
font-family: sans-serif;
text-align: center;
width: 160px;
margin: auto;
display: flex;
flex-direction: column;
}
section {
display: flex;
}
button {
flex: 1;
}
span {
font-size: 20px;
}
And now the design should update to look like:

The useState Hook
In order to add state to the Counter
Component we will first need to import the useState
Hook from React
. useState
is one of the 3 Basic Hooks as per the Official React Doc.
A Word On Hooks
Hooks were introduced in React Version 16.8
. Before hooks, all state needed to be placed within a Class
component.
Hooks introduce state management to Functional
components, using a simpler and more flexible API and let you split one component into smaller functions based on what pieces were needed.
⏰ Activity - 2min
Since we will be working with Hooks
solely in this class let's take a minute to review the following React Docs:
- Hooks API Reference - all the available Hooks
- Beta React Docs
Importing useState
Now it's time to import useState
into the Counter Component.
Since we are familiar with Object Destructuring
let's use it to elicit the value of this key and store in a variable simultaneously.
import { useState } from 'react';
Just so that we get a better idea of what useState
actually is let's add a console log.
export default function Counter(props) {
console.log('useState - ', useState)
// ...rest of code
}
The output should look like the following:

It appears that useState
is a function that takes in in initialState
, calls a supporting function and returns dispatcher.useState()
.
We won't get into the underlying code here but one thing to to highlight is the keyword dispatcher
.
We will revisit this concept later when we cover the useReducer
hook as it uses a similar naming convention of dispatch
for corresponding setState
function.
useState Rules and Best Practices
Let's take a moment to once again review the rules
of useState
and include some best practices as well.
:oncomingpolicecar: - Rules
- the State value is never updated directly
- the State value is only updated using it's corresponding
setState
function - the state value must always be overwritten with a new value
:star: - Best Practices
- Use
Array Destructuring
when initializing the state variables - Name the initial state based on what it contains
- Use the same name for the function but precede it with the word
set
- Use a the callback function version of useState if you need to reference the previous version of state
- Give thought as to what needs to be in state and how that state should be organized and structured
- Always use
...spread
operator to copy object and array values to the new state
Creating An Instance Of State
With useState
imported it's time to create an instance of state. To do this we will call useState()
and pass it an initial starting value of 0
.
:star: Name the initial state based on what it contains.
const countState = useState(0);
Once again let's add a console log and see what it returns.
const countState = useState(0);
console.log('countState -', countState);
We should see the following:

So it appears countState
is set to an array that contains the following elements:
- 0 - the initial state value we defined
- a
function
- which will be used to update state.
One way to create 2 new variables based on the array would be to manually elicit their values using standard array bracket notation.
In keeping with best practices we will name the initial state variable count
as it will be used it to increment/decrement a starting value essentially keep count
.
:star: Use the same name for the function but precede it with the word set
Of course, the corresponding function that will be used to update state should be called setCount
.
:star: Use the same name for the function but precede it with set
const count = countState[0];
const setCount = countState[1];
Array Destructuring
:star: A more convenient way of doing this is using ES6 Array Destructuring.
Array Destructuring elicits the values from the array based on their position and stores them in variables.
const [count, setCount] = useState(0);
Using State
Now that our initial value is been assigned to the count
variable let's update the JSX to use that value instead of a current hard coded value of 0.
Of course, as has been stated several times already, JSX requires that all JavaScript be surrounded in curly braces.
return (
<div>
<span>Current Count: {count}</span>
... rest of code
</div>
);
Updating State
With our state value in place it's time to provide some functionality to the buttons and allow the user a means to interact with the app and update state.
In the case of our Counter the only way to update count
is to call the setCount
function and pass it a new value.
:oncomingpolicecar: Always use the setState
function to update state
There are 2 ways to perform this action:
// grab the current version of state
setCount(count + 1);
// OR
// use a callback function and pass the previous version of state
setCount((prevState) => prevState + 1);
In the second example the setter function takes in an callback function that is passed the previous value of state and returns a new value altogether.
The argument in this example is called prevState
by convention but you can name it anything you want.
There are scenarios when the callback function version is required such as when state is being updated within the callbacks of either a setTimeout()
or setInterval()
. Since that isn't the case here we will use the first example to update state.
Adding an onClick Event
In order to allow the user to interact with the buttons we will need to add an event listener.
React event listeners are an additional topic we will revisit again in future lessons. They are essentially synthetic events
based on the real underlying JS events and perform the same operations as before. Events you might have worked with before are:
- click => onClick
- submit => onSubmit
- change => onChange
- mouseover => onMouseOver
For now we will add an onClick
event listener that calls setCount
to update state.
Also, as with plain JavaScript or jQuery we will use an anonymous callback to pause the execution until the click event has occurred.
return (
<div>
<span>Current Count: {count}</span>
<section>
<button onClick={() => setCount(count + 1)}>+</button>
<button onClick={() => setCount(count - 1)}>-</button>
</section>
</div>
)
If we test out the app we should see that the count value will change based on user input.
Event Handlers
Working with React certainly requires that we write code in very specific and opinionated ways which is why it's considered a Framework
. That is a good thing in that we can quickly examine code and expect some consistency in how it is written.
But some React code is written solely based on the adoption of the community at large. One such pattern is the naming convention when creating event handler
functions. The convention is to precede their name with word handle
.
Let's give that a try by creating the following supporting functions:
handleIncrement
handleDecrement
const handleIncrement = () => {};
const handleDecrement = () => {};
Now let's move the setState
function calls into their corresponding handler
functions and update the onClick
to reflect this refactor.
const handleIncrement = () => {
setCount(count + 1);
};
const handleDecrement = () => {
setCount(count - 1);
};
Thinking Critically
How would you update the onClick's to use your new handler
functions