From my experience as an instructor state and props can really throw React beginners for a loop. The good news is that loop doesn't need to be endless (😅).
State & Props: What Are They?
props(short for “properties”) andstateare both plain JavaScript objects. While both hold information that influences the output of render, they are different in one important way:propsget passed to the component (similar to function parameters) whereasstateis managed within the component (similar to variables declared within a function).
Uh, yeah, okay... but what does that mean? Well, let's take a look at a real world example. Think way back to your grade school days. Remember field trips? And permission slips?
Your mom, dad or parental guardian had to sign a permission slip in order for you to go on a field trip. You brought that permission slip to your teacher and showed it to them to prove that you were allowed to go. This is a great way to think about state and props.
I'm going to use hooks and functional components in these examples, but class components will work, too.
Starting out, the browser looks like this:

The Parent component is rendered in App.js. Here is the starting code for both Parent and Child:
import Child from './Child';
const Parent = () => {
return (
<div className="container">
<div className="parent">
<h2>I am the parent.</h2>
</div>
<div className="child">
<Child />
</div>
</div>
);
};
export default Parent;
and here is the starting code for Child:
const Child = () => {
return (
<div className="child-component">
<h3>I am the child.</h3>
</div>
);
};
export default Child;
The first thing we're going to do is set up state in our Parent component.
const [isSigned, setIsSigned] = useState(false);
const location = "the science museum";
The permission slip for the science museum begins in an unsigned state. Now we need to set up some way for our Parent to sign the permission slip for their child. We'll stick to a simple click event on a button. The button will also render conditionally, based on the value of our isSigned state.
const handleClick = () => {
isSigned ? setIsSigned(false) : setIsSigned(true);
};
const renderButton = () => {
return !isSigned ? <button onClick={handleClick}>Sign Permission Slip</button> : <button onClick={handleClick}>You're Grounded!</button>
};
We now want to invoke renderButton right under our h2 tag in the Parent component. This is what we see in the browser now:

In order to make sure our button actually works, we're going to add {console.log(isSigned)} inside of our Parent component. Our code should look something like this:
const Parent = () => {
const [isSigned, setIsSigned] = useState(false);
const location = "the science museum";
const handleClick = () => {
isSigned ? setIsSigned(false) : setIsSigned(true);
};
const renderButton = () => {
return !isSigned ? <button onClick={handleClick}>Sign Permission Slip</button> : <button onClick={handleClick}>You're Grounded!</button>
};
return (
<div className="container">
{console.log(isSigned)}
<div className="parent">
<h2>I am the parent.</h2>
{renderButton()}
</div>
<div className="child">
<Child />
</div>
</div>
);
};
This is what we should see after our first button click:

and if we click one more time:

Now that we know everything is working correctly in our Parent component, we can start thinking about props! Our Child needs some way to tell their teacher whether they can or cannot go on the field trip. We need to pass this information down to our Child.
<div className="child">
<Child location={location} isSigned={isSigned} />
</div>
This is how we pass information from parent to child. In our Child component, we pass the props in as an argument.
const Child = (props) => {
console.log(props)
return (
<div className="child-component">
<h3>I am the child.</h3>
</div>
);
};
With that console.log, we'll see this in browser console:

We can make things a little cleaner here by using destructuring!
const Child = ({ location, isSigned }) => {
console.log(location)
console.log(isSigned)
return (
<div className="child-component">
<h3>I am the child.</h3>
</div>
);
};
export default Child;
Now that we have access to that data in our Child component, we can display that data!
In the Child component, we now have a function called renderPermission, which renders text conditionally based on the value of isSigned.
const Child = ({ location, isSigned }) => {
const renderPermission = () => {
if (isSigned) {
return `I can go on the field trip to the ${location}!`
} else {
return `I'm not allowed to go on the field trip to the ${location}.`
};
};
return (
<div className="child-component">
<h3>I am the child.</h3>
{renderPermission()}
</div>
);
};
export default Child;
Remember that we can't change props! A kid can't forge their parent/guardians signature! Let's try it out.
const forgePermission = () => {
console.log('Clicked')
isSigned = true;
};
return (
<div className="child-component">
<h3>I am the child.</h3>
<button onClick={forgePermission}>Forge Signature</button> <br />
{renderPermission()}
</div>
);
We're including a console.log so that we can be sure that our event listener is working.
We can't do it! They're not changing! Our Child component is not re-rendering. Our parent component is in charge of the data and changing it (with state!) and our child component only has the ability to display that data (they're props!).
Here is a look at our finished code:
import { useState } from 'react';
import Child from './Child';
const Parent = () => {
const [isSigned, setIsSigned] = useState(false);
const location = "the science museum";
const handleClick = () => {
isSigned ? setIsSigned(false) : setIsSigned(true);
};
const renderButton = () => {
return !isSigned ? <button onClick={handleClick}>Sign Permission Slip</button> : <button onClick={handleClick}>You're Grounded!</button>
};
return (
<div className="container">
<div className="parent">
<h2>I am the parent.</h2>
{renderButton()}
</div>
<div className="child">
<Child location={location} isSigned={isSigned} />
</div>
</div>
);
};
export default Parent;
const Child = ({ location, isSigned }) => {
const renderPermission = () => {
if (isSigned) {
return `I can go on the field trip to the ${location}!`
} else {
return `I'm not allowed to go on the field trip to the ${location}.`
};
};
const forgePermission = () => {
console.log('Clicked')
isSigned = true;
};
return (
<div className="child-component">
<h3>I am the child.</h3>
<button onClick={forgePermission}>Forge Signature</button> <br />
{renderPermission()}
</div>
);
};
export default Child;
That's it! That's state and props in React. It's as simple as that.
Cover image from Austin Pacheco on Unsplash




Top comments (0)