Everything You Need to Know About Props in React

Everything You Need to Know About Props in React

ยท

15 min read

Prop is a very common term in React.

It is one of the must-know concepts for React beginners as you will always use props in most of your React applications.

In this article, you will learn the meaning of props in depth, how to use it, how to pass it as values and functions.

You will also learn how to pass props of different data types, how to pass elements as props and how to create children props.

Prerequisite

  1. HTML, CSS and JavaScript

  2. Basics of React and Next.js

What is a Prop

Prop in React is short term for property. Props means properties.

To understand React properties better, think about how properties work in JavaScript.

Properties in JavaScript Object

Objects are widely used in vanilla JavaScript. They are variables too, but can contain many values.

Using a real life example, a car can be an object. It has many properties like color, name, model and weight.

In JavaScript, we can create a car variable to be an object that has these 4 properties.

let car = {
    name: "Tesla",
    color: "Black",
    model: 3,
    weight: "1800kg",
}

You can use this JavaScript object in your web applications and you can also choose to use one property.

console.log(car.name) // "Tesla"

Props are used to pass data from one React component to another. It is used to make components more dynamic and reusable by allowing them to receive values from their parent components.

React Components

React uses reusable components.

React components are not exactly like objects, they are JavaScript functions but behave like object because they also have properties (props). React components can have props gotten from it's parent component. I wrote about creating React components, importing and exporting them here.

React components returns a React user interface (UI) element which is a representation of the web structure, just like an object describes a structure with properties.

We will be following this file structure from here.

I created a Next.js app and installed Tailwind CSS.

Here's a basic functional component, created in the ChildComponent.jsx file.

// React functional component

// ChildComponent.jsx

import React from "react";

const ChildComponent = () => {
  return (
    <div>
      <h1>Hello World!</h1>
    </div>
  );
};

export default ChildComponent;

React component's functions must start with capital letter as seen in ChildComponent.

We can use this component in our Home page this way.

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent />
    </div>
  );
}

It worked!

Let's pass our first prop to ChildComponent.

Creating Props

It is logical to create props in the parent component of ChildComponent which is app.js and pass it down to ChildComponent, the child component.

Lets create a variable in app.js, use it in app.js, pass it down to ChildComponent and also use it in ChildComponent.

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {

  let carName = "Tesla"

  return (
    <div>
      <h1>Home page {carName}</h1>
      <ChildComponent />
    </div>
  );
}

In the app.js file, we created a variable named carName with a value of "Tesla".

It gets rendered to the page with {carName} in the h1 element.

It worked.

Passing Props

Let's pass this variable to ChildComponent.

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {

  let carName = "Tesla"

  return (
    <div>
      <h1>Home page {carName}</h1>
      <ChildComponent carName={carName} />
    </div>
  );
}

Note how we passed the carName variable. That way, it is used as a property for ChildComponent.

Props are read-only. In the child component where props are passed to, they shouldn't be modify as it goes against the idea of using props or rules of React. Props are created in the parent components and passed to child components to be used in the child components.

Using Props

In the ChildComponent file, we can use it this way.

// ChildComponent.jsx

import React from "react";

const ChildComponent = (props) => {
  console.log(props);
  return (
    <div>
      <h1>Hello World! {props.carName}</h1>
    </div>
  );
};

export default ChildComponent;

You need to put a parameter in the function. I wrote about parameter here.

The parameter is the props. The props is an object.

This is the value of props when I console.logged it:

You can then have access to the carName value in the component with {props.carName} .

It works in the browser.

Let's look at naming props.

Naming Props

You can use any name when passing props.

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {

  let carName = "Tesla"

  return (
    <div>
      <h1>Home page {carName}</h1>
      <ChildComponent nameOfCar={carName} />
    </div>
  );
}

The actual value of the prop is "Tesla" and it is stored in carName variable. To pass the variable, you can give it any name.

In the code above, I named the prop nameOfCar while passing it.

Here's how to use it in the ChildComponent.

// ChildComponent.jsx

import React from "react";

const ChildComponent = (props) => {
  return (
    <div>
      <h1>Hello World! {props.nameOfCar}</h1>
    </div>
  );
};

export default ChildComponent;

It still works the same way!

You can also pass more than one prop.

Passing Multiple Props

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {

  let carName = "Tesla"

  return (
    <div>
      <h1>Home page {carName}</h1>
      <ChildComponent nameOfCar={carName} model={3} />
    </div>
  );
}

Note that we are putting 3 in a curly braces. The curly braces are used to include a JavaScript expression within JSX, that is within the element we are returning.

We can use multiple props this way.

// ChildComponent.jsx

import React from "react";

const ChildComponent = (props) => {
  return (
    <div>
      <h1>Hello World!</h1>
      <p>
        My favourite car is {props.nameOfCar} with model {props.model}
      </p>
    </div>
  );
};

export default ChildComponent;

This works.

In real world web projects, props are usually more than one and anytime we need a prop, we write the props. keyword. This can quickly make our code lengthy.

There's a better way to do this. Destructure the props object parameter.

Destructuring Props

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ nameOfCar, model }) => {
  return (
    <div>
      <h1>Hello World!</h1>
      <p>
        My favourite car is {nameOfCar} with model {model}
      </p>
    </div>
  );
};

export default ChildComponent;

It still works the same way. Click here to read about object destructuring.

Here's what's going on.

// before destructuring

const ChildComponent = (props) => {
.....
}

props = { nameOfCar: "Tesla", model: 3 }
props.nameOfCar = "Tesla"
props.model = 3

// to destructure

const ChildComponent = ({ nameOfCar, model }) => {
....
} 

nameOfCar = "Tesla"
model = 3

Destructuring makes you write less code and makes your overall code cleaner, especially when passing multiple props.

You can pass different data types as props in React. Variables, strings, numbers, objects, arrays and functions can be passed.

Let's go in depth with each of them.

Types of Props to Pass

In each examples below, you will learn

  • different data types to pass as props,

  • how to pass these props from parent component (app.js) to the child component (ChildComponent.jsx) and

  • how to use those props in the child component.

Primitive values:

You can pass primitive values like string, booleans and numbers.

Creating props:

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent name="Tesla" model={3} isFast={true} />
    </div>
  );
}

Using props:

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ name, model, isFast }) => {
  return (
    <div>
      <h1>
        My favourite car is {name}, model {model} and it is very {isFast ? "fast" : "slow" }
      </h1>
    </div>
  );
};

export default ChildComponent;

isFast is a boolean set to true from the parent component.

A conditional rendering is also used here.

{isFast ? "fast" : "slow" }

The code above means if isFast is true, render "fast" else render "slow" if isFast is false.

Browser:

Variables

You can pass variables as seen earlier.

Creating props:

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  let name = "Tesla";
  let model = "3";
  let isFast = true;

  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent name={name} model={model} isFast={isFast} />
    </div>
  );
}

Using props:

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ name, model, isFast }) => {
  return (
    <div>
      <h1>
        My favourite car is {name}, model {model} and it is very {isFast ? "fast" : "slow" }
      </h1>
    </div>
  );
};

export default ChildComponent;

Browser:

Objects

You can pass a whole object as prop and use the object properties in the child components.

Creating props:

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  let car = {
    name: "Tesla",
    color: "Black",
    model: 3,
    weight: "1800kg",
    isFast: true
  };

  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent car={car} />
    </div>
  );
}

Using props:

// ChildComponent.jsx

import React from "react";

const ChildComponent = (prop) => {
  console.log(prop);
  console.log(prop.car);
  const { name, color, model, weight, isFast } = prop.car;
  return (
    <div>
      <h1>
        My favourite car is {name}, model {model} and it is very
        {isFast ? "fast" : "slow"}
      </h1>
    </div>
  );
};

export default ChildComponent;

Note that car is an object on its own. It is passed as a prop to the ChildComponent file.

// from ChildComponent.jsx

prop = {
  car: {
    name: 'Tesla',
    color: 'Black',
    model: 3,
    weight: '1800kg',
    isFast: true
  }
}

// prop is an object that has car object as it's property.
// car object will be accessed with prop.car

prop.car = {
    name: 'Tesla',
    color: 'Black',
    model: 3,
    weight: '1800kg',
    isFast: true
}

To destructure the prop.car object,

const { name, color, model, weight, isFast } = prop.car;

// name = "Tesla", color = "Black",
// model = 3, weight = "1800kg", isFast = true.

// After destructuring, the code below will work.

<h1>
    My favourite car is {name}, model {model} and it is very
    {isFast ? "fast" : "slow"}
</h1>

// color and weight is destructured but never used.
// if you're sure you won't use them, you can destructure this way.

const { name, model, isFast } = prop.car;

Browser:

Arrays

Arrays can also be passed.

Creating props:

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  let car = ["Tesla", "Black", 3, "900kg", true];

  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent car={car} />
    </div>
  );
}

Using props:

// ChildComponent.jsx

import React from "react";

const ChildComponent = (prop) => {
  const [name, color, model, weight, isFast] = prop.car;
  return (
    <div>
      <h1>
        My favourite car is {name}, color {color} and model {model}. It is very
        {isFast ? " fast" : " slow"} and weighs {weight}.
      </h1>
    </div>
  );
};

export default ChildComponent;

prop.car is an array not an object, so it is destructured with the square bracket [ ].

// app.js
let car = ["Tesla", "black", 3, "900kg", true];

// ChildComponent.jsx

const ChildComponent = (prop) => {
    const [name, color, model, weight, isFast] = prop.car;
....
}

// name = Tesla 
// color = black
// model = 3
// weight = 900kg
// isFast = true

Browser:

We can also pass array of objects.

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  let car = [
    {
      name: "Tesla",
      color: "Black",
      model: 3,
      weight: "1800kg",
    },
    { name: "Ford",
      color: "Blue",
      model: "Mustang",
      weight: "1770kg" 
  }];

  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent car={car} />
    </div>
  );
}

Using props:

// ChildComponent.jsx

import React from "react";

const ChildComponent = (prop) => {
  const { car } = prop;

  return (
    <div>
      {car.map(car => (
        <h1>
        My favourite car is {car.name}, color {car.color} and model {car.model}. It is very
        {car.isFast ? " fast" : " slow"} and weighs {car.weight}.
      </h1>
      ))}
    </div>
  );
};

export default ChildComponent;

Note that car is an array of objects.

// from ChildComponent.jsx

prop = {
  car = [
    {
      name: "Tesla",
      color: "Black",
      model: 3,
      weight: "1800kg",
    },
    { name: "Ford",
      color: "Blue",
      model: "Mustang",
      weight: "1770kg" 
  }];
}

// prop is an object that has car array as it's property.
// car array will be accessed with prop.car

prop.car = [
    {
      name: "Tesla",
      color: "Black",
      model: 3,
      weight: "1800kg",
    },
    { name: "Ford",
      color: "Blue",
      model: "Mustang",
      weight: "1770kg" 
  }];

// We destructured the car array,

const { car } = prop;

car = [
    {
      name: "Tesla",
      color: "black",
      model: 3,
      weight: "1800kg",
    },
    { name: "Ford",
      color: "blue",
      model: "mustang",
      weight: "1770kg" 
}];

// By now you should have know a better way of writing the code below

const ChildComponent = (prop) => {
  const { car } = prop;
....

// The above code should have been written as
const ChildComponent = ({ car }) => {
  ...
// car is destrutured in the parameter ()
// After destructuring, car is an array of objects and can be used.

<div>
      {car.map((car) => (
        <h1>
          My favourite car is {car.name}, color {car.color} and model {car.model}.
          It is very
          {car.isFast ? " fast" : " slow"} and weighs {car.weight}.
        </h1>
      ))}
</div>

// The div above can also be simplified this way.

{car.map(({ name, color, model, isFast, weight }) => (
  <h1>
    My favourite car is {name}, color {color}, model {model}. It is very
    {isFast ? " fast" : " slow"} and weighs {weight}.
  </h1>
))}

// We are destructuring each object in the array as we map over the array.

Read more about map method here.

Browser:

Functions

Functions created in the parent component can be used in the parent component and passed to the child component to be used.

// app.js

"use client";

import React, { useState } from "react";
import ChildComponent from "../components/ChildComponent";

export default function Home() {
  const [isColorChanged, setColorChanged] = useState(false);

  const buttonStyle = {
    backgroundColor: isColorChanged ? "red" : "blue",
    margin: "3px",
    padding: "5px",
    color: isColorChanged ? "black" : "white",
    borderRadius: "5px",
  };

  const handleClick = () => {
    setColorChanged(!isColorChanged);
  };

  return (
    <div>
      <h1>Home page</h1>
      <button style={buttonStyle} onClick={handleClick}>
        Change color from parent component
      </button>
      <ChildComponent changeColorFunction={handleClick} buttonStyle={buttonStyle} />
    </div>
  );
}

useState is imported from React to store the state of isColorChanged boolean value, isColorChanged is false initially. Read more about useState here.

"use client" is referenced at the top level to make useState work. Read about "use client" and why we need to use it here.

Button styles is created in an object and saved in the buttonStyle variable. Note the background color and color styles are dynamic. When isColorChanged is true, red and black color is selected respectively. Blue and white color are also selected for background color and color respectively when isColorChanged is false.

  const buttonStyle = {
    backgroundColor: isColorChanged ? "red" : "blue",
    margin: "3px",
    padding: "5px",
    color: isColorChanged ? "black" : "white",
    borderRadius: "5px",
  };

A function was created called handleClick to change the state of isColorChanged.

When isColorChanged is false, calling the function changes isColorChanged to true, but when isColorChanged is true, the function changes it to false.

const handleClick = () => {
  setColorChanged(!isColorChanged);
};

buttonStyle was attached to the button element as it's styles. handleClick was also added as a function to be called when the button is clicked.

<button style={buttonStyle} onClick={handleClick}>
  Change color from parent component
</button>

The handleClick function and buttonStyle styles was passed as a prop to the ChildComponent child component.

handleClick was named as onColorChange.

 <ChildComponent onColorChange={handleClick} buttonStyle={buttonStyle} />

Using prop:

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ changeColorFunction, buttonStyle }) => {

  return (
    <div>
      <h3>Child Component</h3>
      <button style={buttonStyle} onClick={changeColorFunction}>
      Change color from child component
      </button>
    </div>
  );
};

export default ChildComponent;

The two props were destructured and used here.

A new button element was created in the child component. It has the passed buttonStyle as it's style and when the button is clicked, the passed changeColorFunction will be called.

When the button is clicked from parent and child component, isColorChanged state is switched and buttonStyle background color and color value are changed.

This will affect both component and thus both button.

Browser:

Elements

You can also pass HTML elements as a prop to the child component.

// app.js

import ChildComponent from "../components/ChildComponent";

export default function Home() {
  const hero = <span>- Hero Text</span>;

  return (
    <div>
      <h1>Home page {hero} </h1>
      <ChildComponent hero={hero} />
    </div>
  );
}

hero is a variable that has a span element as it's value. It is used in the parent component and also passed down to ChildComponent.

Using prop:

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ hero }) => {
  return (
    <div>
      <h2>Child Component page {hero} </h2>
    </div>
  );
};

export default ChildComponent;

hero is destructured and used here.

Browser:

Children

Props can also be content between the opening and closing tag of the child component. They are called children prop.

// app.js

import React from "react";
import ChildComponent from "../components/ChildComponent";

export default function Home() {
  return (
    <div>
      <h1>Home page</h1>
      <ChildComponent>
        <p>This is a child element.</p>
      </ChildComponent>
    </div>
  );
}

The p element is written between the opening and closing tag of ChildComponent. It is automatically passed as prop to the ChildComponent child component.

Using prop:

// ChildComponent.jsx

import React from "react";

const ChildComponent = ({ children }) => {
  return (
    <div>
      <h2>Child Component</h2>
      {children}
    </div>
  );
};

export default ChildComponent;

The prop is accessed as children. It is destructured here.

// ChildComponent.jsx

const ChildComponent = ({ children }) => {
...
}

The prop which is the p element will be rendered after the h2 element.

<h2>Child Component</h2>
{children}

Browser:

Conclusion

Working with React will always involve using props. Where you create props will determine where to pass it and how to use it.

Destructuring props will make your code clean and easy to read.

That will be all. Hope you found value here as you learn to build more projects effectively.

If you enjoyed this article and want to see more content related to JavaScript and Web development, then follow me here, Twitter (X) or connect on LinkedIn. I'd be happy to count you as one of my ever-growing group of awesome friends on the internet.

You can also join my WhatsApp community of 280+ developers learning and building cool projects.

If you also want to support me, you can buy a cup of coffee for me here.

Thanks && Bye. ๐Ÿ‘‹