Table of Contents
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:
1const Banner = props => {2 const name = props.name3 return <div>Hello {name}</div>4}56function App() {7 return (8 <div>9 <Banner name="Abhishek" />10 </div>11 )12}1314export 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:
1const Banner = props => {2 const name = props.name3 return (4 <div>5 <p>Hello {name}</p>6 <button onClick={props.clickHandler}>Click Me</button>7 </div>8 )9}1011function App() {12 const showAlert = () => {13 alert("Welcome!")14 }15 return (16 <div>17 <Banner name="Abhishek" clickHandler={showAlert} />18 </div>19 )20}2122export 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
:
1const Banner = props => {2 const name = props.name3 return <div>{props.show && <p>Hello {name}</p>}</div>4}56function App() {7 return (8 <div>9 <Banner name="Abhishek" show />10 </div>11 )12}1314export 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:
1import { useState } from "react"23const Banner = props => {4 const name = props.name5 return (6 <div>7 <p>8 {props.greeting} {name}9 </p>10 </div>11 )12}1314function App() {15 const [greeting, setGreeting] = useState("Hello")16 return (17 <div>18 <Banner name="Abhishek" greeting={greeting} />19 </div>20 )21}2223export default App
Also, you can modify the parent state by passing a function to the child component as follows
1import { useState } from "react"23const Banner = props => {4 const name = props.name5 return (6 <div>7 <p>8 {props.greeting} {name}9 </p>10 <button onClick={props.changeGreeting}>Change greeting</button>11 </div>12 )13}1415function App() {16 const [greeting, setGreeting] = useState("Hello")1718 const changeGreeting = () => {19 setGreeting("Howdy")20 }21 return (22 <div>23 <Banner24 name="Abhishek"25 greeting={greeting}26 changeGreeting={changeGreeting}27 />28 </div>29 )30}3132export 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:
1const UserCard = props => {2 const name = props.user.name3 const role = props.user.role4 const age = props.user.age5 const profilePic = props.user.profilePic6 return (7 <div>8 <p>Name: {name}</p>9 <p>Role: {role}</p>10 <p>Age: {age}</p>11 <img src={profilePic} alt={name} />12 </div>13 )14}1516function App() {17 const user = {18 name: "Abhishek",19 role: "Software Engineer",20 age: 27,21 profilePic: "image.jpg",22 }2324 return (25 <div>26 <UserCard user={user} />27 </div>28 )29}3031export 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:
1const UserCard = props => {2 const name = props.name3 const role = props.role4 const age = props.age5 const profilePic = props.profilePic6 return (7 <div>8 <p>Name: {name}</p>9 <p>Role: {role}</p>10 <p>Age: {age}</p>11 <img src={profilePic} alt={name} />12 </div>13 )14}1516function App() {17 const user = {18 name: "Abhishek",19 role: "Software Engineer",20 age: 27,21 profilePic: "image.jpg",22 }2324 return (25 <div>26 <UserCard27 name={user.name}28 role={user.role}29 age={user.age}30 profilePic={user.profilePic}31 />32 </div>33 )34}3536export 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
1const UserCard = props => {2 const name = props.name3 const role = props.role4 const age = props.age5 const profilePic = props.profilePic6 return (7 <div>8 <p>Name: {name}</p>9 <p>Role: {role}</p>10 <p>Age: {age}</p>11 <img src={profilePic} alt={name} />12 </div>13 )14}1516function App() {17 const user = {18 name: "Abhishek",19 role: "Software Engineer",20 age: 27,21 profilePic: "image.jpg",22 }2324 return (25 <div>26 <UserCard {...user} />27 </div>28 )29}3031export 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.
1const UserCard = ({ name, role, age, profilePic }) => {2 return (3 <div>4 <p>Name: {name}</p>5 <p>Role: {role}</p>6 <p>Age: {age}</p>7 <img src={profilePic} alt={name} />8 </div>9 )10}1112function App() {13 const user = {14 name: "Abhishek",15 role: "Software Engineer",16 age: 27,17 profilePic: "image.jpg",18 }1920 return (21 <div>22 <UserCard {...user} />23 </div>24 )25}2627export 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:
1const Banner = props => {2 const name = props.name || "user"3 return <div>Hello {name}</div>4}56function App() {7 return (8 <div>9 <Banner />10 </div>11 )12}1314export default App
Using default parameters
We can also specify a default parameter while destructing the props:
1const Banner = ({ name = "user" }) => {2 return <div>Hello {name}</div>3}45function App() {6 return (7 <div>8 <Banner />9 </div>10 )11}1213export default App
Using defaultProps
There is another way to explicitly specify the default props in React. This is the most recommended approach:
1const Banner = ({ name }) => {2 return <div>Hello {name}</div>3}45function App() {6 return (7 <div>8 <Banner />9 </div>10 )11}1213Banner.defaultProps = {14 name: "user",15}1617export 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:
1const UserCard = ({ name, role: occupation }) => {2 return (3 <div>4 <p>Name: {name}</p>5 <p>Occupation: {occupation}</p>6 </div>7 )8}910function App() {11 return (12 <div>13 <UserCard name="Abhi" role="Software Engineer" />14 </div>15 )16}1718export 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:
1const UserCard = ({ name, children }) => {2 return (3 <div>4 <p>Name: {name}</p>5 {children}6 </div>7 )8}910const UserIcon = ({ profilePic }) => {11 return <img src={profilePic} alt="profile" />12}1314function App() {15 return (16 <div>17 <UserCard name="Abhi">18 <UserIcon profilePic="image.jpg" />19 </UserCard>20 </div>21 )22}2324export 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:
1const UserCard = ({ name, icon }) => {2 return (3 <div>4 <p>Name: {name}</p>5 {icon}6 </div>7 )8}910const UserIcon = ({ profilePic }) => {11 return <img src={profilePic} alt="profile" />12}1314function App() {15 return (16 <div>17 <UserCard18 name="Abhi"19 icon={<UserIcon profilePic="image.jpg" />}20 ></UserCard>21 </div>22 )23}2425export 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.
Do follow me on twitter where I post developer insights more often!