DEV Community

Cover image for The State of Taking Props to School
Ronnie
Ronnie

Posted on

The State of Taking Props to School

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?

Very Confused Little Girl

props (short for “properties”) and state are both plain JavaScript objects. While both hold information that influences the output of render, they are different in one important way: props get passed to the component (similar to function parameters) whereas state is managed within the component (similar to variables declared within a function).

Reactjs.com - Component State

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:
Browser with two divs, "I am the parent." and "I am the child."

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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";
Enter fullscreen mode Exit fullscreen mode

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>
};
Enter fullscreen mode Exit fullscreen mode

We now want to invoke renderButton right under our h2 tag in the Parent component. This is what we see in the browser now:
Parent and Child component with button

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

This is what we should see after our first button click:
Signed Permission Slip

and if we click one more time:
Field trip permission: revoked!

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>
Enter fullscreen mode Exit fullscreen mode

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>
  );
};
Enter fullscreen mode Exit fullscreen mode

With that console.log, we'll see this in browser console:
Console log of props

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;
Enter fullscreen mode Exit fullscreen mode

Props with destructuring

Now that we have access to that data in our Child component, we can display that data!

Functioning permission slip signing

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;
Enter fullscreen mode Exit fullscreen mode

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>
  );
Enter fullscreen mode Exit fullscreen mode

We're including a console.log so that we can be sure that our event listener is working.

A child can't change props

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;
Enter fullscreen mode Exit fullscreen mode
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;
Enter fullscreen mode Exit fullscreen mode

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)