As you learn how to develop web applications using React, you will inevitably come across the concept of props. Understanding the way props work is essential to mastering React, but to grasp the concept fully is no easy thing.
Props in React: an introduction
Props stands for “properties,” and they are used in a React application to send data from one React component to another React component. Let’s take a look at the example code below. Here we have a single React component rendering a string:
import React, { Component } from "react"; import ReactDOM from "react-dom"; class App extends Component { render(){ return <div>Hello, World!</div> } } ReactDOM.render(<App />, document.getElementById("root"));
Now here’s how you add props into the App
component: right beside the call to the App component on ReactDOM.render
, type a random property and assign it a value. I will create a name
property and assign it as “Nathan”
:
import React, { Component } from "react"; import ReactDOM from "react-dom"; class App extends Component { render(){ return <div>Hello, World!</div> } } ReactDOM.render(<App name="Nathan" />, document.getElementById("root"));
And with that, the App
component now has a props called name
; you can call on it from the class using this
. Let me show you how I greet myself:
import React, { Component } from "react"; import ReactDOM from "react-dom"; class App extends Component { render(){ return <div>Hello, {this.props.name}!</div> } } ReactDOM.render(<App name="Nathan" />, document.getElementById("root"));
This is the very basis of props: it allows you to send any data you can think of into a component when you call on that component. When you have two components or more, you can pass data around. Here’s another example with two components:
As the code above demonstrates, you can pass props between components by adding them when the component is being called, just like you pass arguments when calling on a regular JavaScript function
. And speaking of functions, since React allows you to create a component using function
as well, let’s see how props work in a function component next.
Props in a function component
In a function component, components receive props exactly like an ordinary function argument. A function component will receive the props
object with properties you described in the component call:
import React from "react"; import ReactDOM from "react-dom"; function App() { return <Greeting name="Nathan" age={27} occupation="Software Developer" />; } function Greeting(props) { return ( <p> Hello! I'm {props.name}, a {props.age} years old {props.occupation}. Pleased to meet you! </p> ); } ReactDOM.render(<App />, document.getElementById("root"));
Aside from passing multiple props at once, in this example, you also see the age
prop is a number data type. This demonstrates that you can pass any type of data available in JavaScript — such as number
, Boolean
, or object
— into props. This is how props enable you to send data using the top-down approach, wherein a component at a higher level can send data to a component below it.
Code reuse with props and state
The use of props allows you to reuse more React code and avoid repeating yourself. In the case of our example, you can reuse the same Greeting
component for many different people:
import React from "react"; import ReactDOM from "react-dom"; function App() { return ( <div> <Greeting name="Nathan" age={27} occupation="Software Developer" /> <Greeting name="Jane" age={24} occupation="Frontend Developer" /> </div> ); } function Greeting(props) { return ( <p> Hello! I'm {props.name}, a {props.age} years old {props.occupation}. Pleased to meet you! </p> ); } ReactDOM.render(<App />, document.getElementById("root"));
That’s great! But since props are read-only and must not be changed manually throughout the lifespan of a React application, using only props in your React app doesn’t really make it a dynamic app that can respond to user interactions and render accordingly. In order to do that, you need to use state
.
States and props together form the data “model” of a React application. While props are meant to be read-only, states are used for data that can change based on user actions. Let’s see how they work together to create a dynamic application.
First, let’s add a new state named textSwitch
that stores a Boolean value to the App
component and pass it to the Greeting
component. The Greeting
component will look to this state value to decide what to render:
This code example shows how you can conditionally render the view of your application based on user actions with state
and props
. In React, states are passed from one component into another component as props. Since prop names and values will just be passed into a component as regular props
object properties, it’s not concerned with where the data is coming from.
propTypes and defaultProps
As you develop your React application, sometimes you might need a prop to be structured and defined to avoid bugs and errors. In the same way a function
might require mandatory arguments, a React component might require a prop to be defined if it is to be rendered properly.
You can make a mistake and forget to pass a required prop into the component that needs it:
import React from "react"; import ReactDOM from "react-dom"; function App() { return <Greeting name="Nathan" />; } function Greeting(props) { return ( <p> Hello! I'm {props.name}, a {props.age} years old {props.occupation}. Pleased to meet you! </p> ); } ReactDOM.render(<App />, document.getElementById("root"));
While props.age
and props.occupation
are undefined in the Greeting
component, React will simply ignore the expression to call on their value and render the rest of the text. It doesn’t trigger any error, but you know you can’t let this kind of thing go unaddressed.
This is where propTypes
comes to help. PropTypes
is a special component property that can be used to validate the props you have in a component. It’s a separate, optional npm package, so you need to install it first before using it:
npm install --save prop-types
Now let’s make required props in the Greeting
component:
import React from "react"; import ReactDOM from "react-dom"; import PropTypes from "prop-types"; function App() { return <Greeting name="Nathan" />; } function Greeting(props) { return ( <p> Hello! I'm {props.name}, a {props.age} years old {props.occupation}. Pleased to meet you! </p> ); } Greeting.propTypes = { name: PropTypes.string.isRequired, // must be a string and defined age: PropTypes.number.isRequired, // must be a number and defined occupation: PropTypes.string.isRequired // must be a string and defined }; ReactDOM.render(<App />, document.getElementById("root"));
With the propTypes
property declared, the Greeting
component will throw a warning to the console when its props aren’t passing propTypes
validation.
You can also define default values for props in cases where props are not being passed into the component on call by using another special property called defaultProps
:
And now the default values in defaultProps
will be used when Greeting
is called without props.
Learn more about default props in React here.
Passing data from child components to parent components
A parent component is any component that calls other components in its code block, while a child component is simply a component that gets called by a parent component. A parent component passes data down to child components using props.
You might wonder, “How can you pass data up from a child component to a parent component?”
The answer is it’s not possible — at least not directly. But here’s the thing in React: you can also pass a function
as props. How is that relevant to the question? Let’s first return to the code example with state
:
import React, { useState } from "react"; import ReactDOM from "react-dom"; function App() { const [textSwitch, setTextSwitch] = useState(true); return ( <div> <button onClick={() => setTextSwitch(!textSwitch)} type="button"> Toggle Name </button> <Greeting text={textSwitch} /> </div> ); } function Greeting(props) { console.log(props.text); if (props.text) { return ( <p> Hello! I'm Nathan and I'm a Software Developer. Pleased to meet you! </p> ); } return ( <p>Hello! I'm Jane and I'm a Frontend Developer. Pleased to meet you!</p> ); } ReactDOM.render(<App />, document.getElementById("root"));
It’s very common for a React application to have as many as three component layers, with the top-layer component calling on a child component that calls on another child component. We need to adjust the example above a bit to illustrate this point.
Let’s move the <button>
element out of App
and into its own component. To make it simple, let’s call it ChangeGreeting
. You will then call on this component from the Greeting
component instead of the App
component:
import React, { useState } from "react"; import ReactDOM from "react-dom"; function App() { const [textSwitch, setTextSwitch] = useState(true); return ( <div> <Greeting text={textSwitch} /> </div> ); } function Greeting(props) { let element; if (props.text) { element = ( <p> Hello! I'm Nathan and I'm a Software Developer. Pleased to meet you! </p> ); } else { element = ( <p>Hello! I'm Jane and I'm a Frontend Developer. Pleased to meet you!</p> ); } return ( <div> {element} <ChangeGreeting /> </div> ); } function ChangeGreeting(props) { return ( <button type="button"> Toggle Name </button> ); } ReactDOM.render(<App />, document.getElementById("root"));
Now the button for setting the state is in the ChangeGreeting
component, which is two layers down from where the state is (at the App
component). So how can you possibly change the state? The answer is that you send a function down until it reaches the component that needs it:
In the example above, the App
component is sending the handleClick
prop, which has the function to change the state into the Greeting
component. The Greeting
component didn’t actually need it, but its child component, ChangeGreeting
, does, so it forwards the prop there.
On the ChangeGreeting
component, it will call on the handleClick
function when the button is clicked, causing App
to execute the function.
When the state in App
is updated, React view is re-rendered, and the new state value is then sent to Greeting
through props.
So, yes — React can’t send data up from a child component into its parent component, but the parent component can send a function to a child component. Knowing this, you can send a function that updates state into the child component, and once that function is called, the parent component will update the state.
More great articles from LogRocket:
- Don't miss a moment with The Replay, a curated newsletter from LogRocket
- Learn how LogRocket's Galileo cuts through the noise to proactively resolve issues in your app
- Use React's useEffect to optimize your application's performance
- Switch between multiple versions of Node
- Discover how to use the React children prop with TypeScript
- Explore creating a custom mouse cursor with CSS
- Advisory boards aren’t just for executives. Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
You can’t send data, but you can send a signal for change using a function.
Prop drilling and how to deal with it
The last example for passing data actually represents another common problem you might encounter when dealing with props and state: prop drilling.
Prop drilling refers to passing props down the component layers until they reach the designated child component, while other higher components don’t actually need them.
It might seem OK in the example above, but keep in mind that we only have three components there. When you have many components, and all of them are interacting with each other using props and state, prop drilling can become a headache to maintain.
In order to avoid this problem, one of the things you can do is keep the number of components down and only create new components when that particular piece of component needs to be reused.
Back to the example, there is absolutely no need for a separate ChangeGreeting
component until another component besides Greeting
actually calls on the same piece of code. You can do this with only two components:
import React, { useState } from "react"; import ReactDOM from "react-dom"; function App() { const [textSwitch, setTextSwitch] = useState(true); return ( <div> <Greeting text={textSwitch} handleClick={() => setTextSwitch(!textSwitch)} /> </div> ); } function Greeting(props) { let element; if (props.text) { element = ( <p> Hello! I'm Nathan and I'm a Software Developer. Pleased to meet you! </p> ); } else { element = ( <p>Hello! I'm Jane and I'm a Frontend Developer. Pleased to meet you!</p> ); } return ( <div> {element} <button onClick={props.handleClick} type="button"> Toggle Name </button> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
There you go — no prop drilling necessary for passing down the props this way.
Passing props in React: conclusion
As with all things about learning React, props are easy to learn but hard to master. Now you know that props are immutable (read-only) data used to make React components “talk” to each other. They are very similar to arguments passed to a function, which can be anything specified by developers themselves.
States and props enable you to create a dynamic React application with a solid codebase that is reusable, maintainable, and data-driven.
Get set up with LogRocket's modern React error tracking in minutes:
- Visit https://logrocket.com/signup/ to get an app ID.
- Install LogRocket via NPM or script tag.
LogRocket.init()
must be called client-side, not server-side. - (Optional) Install plugins for deeper integrations with your stack:
- Redux middleware
- ngrx middleware
- Vuex plugin
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
Thank you for proving detail information for How to pass props to components in React. this steps is really helpful on my current project.
Curious question.
Sometimes ( Mostly 🙁 ) I do this inside child components before the return fucntion.
const {
article,
show,
created,
lines,
onClick
} = props;
Then i use this inside th return.
I do to save myself writing this.props before every variable.
Is this bad practice ?
Daniel
Hey Daniel it’s the author here. No, it’s actually common practice to destructure the props before using them, so relax 🙂
You’re welcome Kirti. Glad you find it useful
Hi, can you explain how pass props to server side in order to use the prop as a key to search a specific documento in a mongodb database ?
I do like this ({ pdf, scrollPdfFrame, zoomInOption }) in functional component