How to pass props to a component in React

How to pass props to a component in React

·

7 min read

What are props?

Consider a function in any programming language. How do we pass values to the function? Using parameters. Props (properties) are similar to parameters. They are used to pass data from one component to another in React. Below is the simplest example on how to pass props:

const Banner = props => {
  const name = props.name
  return <div>Hello {name}</div>
}

function App() {
  return (
    <div>
      <Banner name="Abhishek" />
    </div>
  )
}

export default App

A couple of things you need to be aware of props are:

  • Props are read-only, they should not be mutated.
  • We cannot pass props from a child component to a parent component. Props always move from top to bottom in the component hierarchy.

Passing functions as Props

We can pass functions as props as well:

const Banner = props => {
  const name = props.name
  return (
    <div>
      <p>Hello {name}</p>
      <button onClick={props.clickHandler}>Click Me</button>
    </div>
  )
}

function App() {
  const showAlert = () => {
    alert("Welcome!")
  }
  return (
    <div>
      <Banner name="Abhishek" clickHandler={showAlert} />
    </div>
  )
}

export default App

As you could see (line 17), the name of the function and the prop need not be the same.

Passing Boolean values

If you specify a prop without any values, it will be treated as a Boolean with value true:

const Banner = props => {
  const name = props.name
  return <div>{props.show && <p>Hello {name}</p>}</div>
}

function App() {
  return (
    <div>
      <Banner name="Abhishek" show />
    </div>
  )
}

export default App

If you need to pass false, then you need to explicitly mention it like:

<Banner name="Abhishek" show={false} />

Passing a state as a prop

You can pass the parent component state as a prop to the child component:

import { useState } from "react"

const Banner = props => {
  const name = props.name
  return (
    <div>
      <p>
        {props.greeting} {name}
      </p>
    </div>
  )
}

function App() {
  const [greeting, setGreeting] = useState("Hello")
  return (
    <div>
      <Banner name="Abhishek" greeting={greeting} />
    </div>
  )
}

export default App

Also, you can modify the parent state by passing a function to the child component as follows

import { useState } from "react"

const Banner = props => {
  const name = props.name
  return (
    <div>
      <p>
        {props.greeting} {name}
      </p>
      <button onClick={props.changeGreeting}>Change greeting</button>
    </div>
  )
}

function App() {
  const [greeting, setGreeting] = useState("Hello")

  const changeGreeting = () => {
    setGreeting("Howdy")
  }
  return (
    <div>
      <Banner
        name="Abhishek"
        greeting={greeting}
        changeGreeting={changeGreeting}
      />
    </div>
  )
}

export default App

Here we are passing the changeGreeting function as a prop to the Banner component, and calling it from the Banner component when the button is clicked. Inside the changeGreeting function, we are modifying the state to 'Howdy'.

Passing objects as Props

Consider the following example:

const UserCard = props => {
  const name = props.user.name
  const role = props.user.role
  const age = props.user.age
  const profilePic = props.user.profilePic
  return (
    <div>
      <p>Name: {name}</p>
      <p>Role: {role}</p>
      <p>Age: {age}</p>
      <img src={profilePic} alt={name} />
    </div>
  )
}

function App() {
  const user = {
    name: "Abhishek",
    role: "Software Engineer",
    age: 27,
    profilePic: "image.jpg",
  }

  return (
    <div>
      <UserCard user={user} />
    </div>
  )
}

export default App

Here we are passing an object to the child component and accessing it like props.user.name. So every time we need to access a property, we need to dig through props.user. This can be avoided by passing them as individual props as shown below:

const UserCard = props => {
  const name = props.name
  const role = props.role
  const age = props.age
  const profilePic = props.profilePic
  return (
    <div>
      <p>Name: {name}</p>
      <p>Role: {role}</p>
      <p>Age: {age}</p>
      <img src={profilePic} alt={name} />
    </div>
  )
}

function App() {
  const user = {
    name: "Abhishek",
    role: "Software Engineer",
    age: 27,
    profilePic: "image.jpg",
  }

  return (
    <div>
      <UserCard
        name={user.name}
        role={user.role}
        age={user.age}
        profilePic={user.profilePic}
      />
    </div>
  )
}

export default App

Still we haven't solved the need to write user. for accessing every prop. We just elevated it to parent component. This syntax can be simplified further using Javascript spread operator

const UserCard = props => {
  const name = props.name
  const role = props.role
  const age = props.age
  const profilePic = props.profilePic
  return (
    <div>
      <p>Name: {name}</p>
      <p>Role: {role}</p>
      <p>Age: {age}</p>
      <img src={profilePic} alt={name} />
    </div>
  )
}

function App() {
  const user = {
    name: "Abhishek",
    role: "Software Engineer",
    age: 27,
    profilePic: "image.jpg",
  }

  return (
    <div>
      <UserCard {...user} />
    </div>
  )
}

export default App

The only change is in line number 26, where instead of passing individual props, we have just passed {...props}.

Destructuring props

If you see the above example, in the child component, we are using props.name, props.age etc for accessing the props. Can we simplify this further? Yes, we can.

const UserCard = ({ name, role, age, profilePic }) => {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Role: {role}</p>
      <p>Age: {age}</p>
      <img src={profilePic} alt={name} />
    </div>
  )
}

function App() {
  const user = {
    name: "Abhishek",
    role: "Software Engineer",
    age: 27,
    profilePic: "image.jpg",
  }

  return (
    <div>
      <UserCard {...user} />
    </div>
  )
}

export default App

As you may observe, we have used JavaScript destructing to access the props directly.

These are just different ways to pass an object to the child component. There is no such thing as the best practice. You may use a style of your choice.

Default props

What if the parent component misses passing a prop? How to make sure our code does not break and there is always a fallback value? We can use default props for that.

Default props can be set using different ways.

Using Short circuit evaluation

We can use the logical OR operator to set a default name as shown below:

const Banner = props => {
  const name = props.name || "user"
  return <div>Hello {name}</div>
}

function App() {
  return (
    <div>
      <Banner />
    </div>
  )
}

export default App

Using default parameters

We can also specify a default parameter while destructing the props:

const Banner = ({ name = "user" }) => {
  return <div>Hello {name}</div>
}

function App() {
  return (
    <div>
      <Banner />
    </div>
  )
}

export default App

Using defaultProps

There is another way to explicitly specify the default props in React.This is the most recommended approach:

const Banner = ({ name }) => {
  return <div>Hello {name}</div>
}

function App() {
  return (
    <div>
      <Banner />
    </div>
  )
}

Banner.defaultProps = {
  name: "user",
}

export default App

Also, you can validate the type of the props using prop-types

Renaming props

If you would like to change the name of the prop, then you can do so as shown below:

const UserCard = ({ name, role: occupation }) => {
  return (
    <div>
      <p>Name: {name}</p>
      <p>Occupation: {occupation}</p>
    </div>
  )
}

function App() {
  return (
    <div>
      <UserCard name="Abhi" role="Software Engineer" />
    </div>
  )
}

export default App

Here we are passing a prop called role from the parent component, which we are renaming to occupation in the child component.

Passing components as children

We can pass a component to another component by wrapping it within the parent component as shown below:

const UserCard = ({ name, children }) => {
  return (
    <div>
      <p>Name: {name}</p>
      {children}
    </div>
  )
}

const UserIcon = ({ profilePic }) => {
  return <img src={profilePic} alt="profile" />
}

function App() {
  return (
    <div>
      <UserCard name="Abhi">
        <UserIcon profilePic="image.jpg" />
      </UserCard>
    </div>
  )
}

export default App

As you may see, we can access the passed component using children prop.

An alternate way to pass a component to the child is using a named prop as shown below:

const UserCard = ({ name, icon }) => {
  return (
    <div>
      <p>Name: {name}</p>
      {icon}
    </div>
  )
}

const UserIcon = ({ profilePic }) => {
  return <img src={profilePic} alt="profile" />
}

function App() {
  return (
    <div>
      <UserCard
        name="Abhi"
        icon={<UserIcon profilePic="image.jpg" />}
      ></UserCard>
    </div>
  )
}

export default App

Hope you have liked the article and have a clear understanding of different ways of passing props in React. Do let me know in the comments below if you have any questions.