Skip to content

Props

Props (short for “properties”) are values passed from a parent component down to a child component. They let you customize a component and reuse it in different places. Props are one of the most important parts of React, because they control how data moves through your components.

graph TD P["Parent Component"] -->|props| C["Child Component"] C --> U["Rendered UI"]

Data Flow

Send data from a parent to a child in a clear, one-way direction.

Reusability

Use the same component again and again, just with different prop values.

Dynamic UI

Show different content depending on the input values you give it.

function App() {
return <User name="Sahil" age={20} />;
}

Props cannot be changed inside the child component - they are read-only. A child should never try to change them directly. If something needs to change, the parent should update its own data and pass new props down instead.

function User(props) {
props.name = "Changed"; // Wrong: never mutate props
}

React follows a one-way data flow: data always moves from parent to child, never the other way around.

Parent -> Child (one-way)

A prop can hold almost any kind of JavaScript value - text, numbers, true/false, arrays, objects, even functions.

<User name="Sahil" age={20} isAdmin={true} />

In class components, you access props using this.props.

class User extends React.Component {
render() {
return <h1>{this.props.name}</h1>;
}
}

You can set a default value for a prop, which gets used when that prop isn’t passed in.

function User({ name = "Guest" }) {
return <h1>{name}</h1>;
}

Props can also pass through more than one level of components in a tree.

App
├── Header
├── User
│ └── Profile
function App() {
return <User name="Sahil" />;
}
function User(props) {
return <Profile name={props.name} />;
}
graph LR A["App"] -->|name| B["User"] B -->|name| C["Profile"]
FeaturePropsState
OwnershipParentComponent
MutabilityImmutableMutable
PurposeData passingInternal logic

props.children holds whatever you put between the opening and closing tags of a component.

function Card(props) {
return <div>{props.children}</div>;
}
<Card>
<h1>Hello</h1>
</Card>
<Card>
v
props.children = <h1>Hello</h1>

Props are often used to decide what to show using conditional logic.

function User({ isLoggedIn }) {
return <h1>{isLoggedIn ? "Welcome" : "Please Login"}</h1>;
}

Spread props are a quick and common way to pass a group of related values all at once.

const user = { name: "Sahil", age: 20 };
<User {...user} />;

Equivalent to:

<User name="Sahil" age={20} />

You can pass functions as props too. This lets a child component trigger an action that the parent controls.

function Parent() {
function handleClick() {
console.log("Clicked");
}
return <Child onClick={handleClick} />;
}
function Child({ onClick }) {
return <button onClick={onClick}>Click</button>;
}
Parent controls behavior
Child triggers it

Whenever props change, React re-renders the component that received them.

New Props -> Re-render -> New UI

Even if the final output looks exactly the same, React may still do the work of re-rendering, unless you specifically optimize it to avoid that.

The key prop helps React keep track of which list item is which, especially when the list changes.

items.map((item) => <li key={item.id}>{item.name}</li>);

Keys should stay the same, be unique for each item, and not change between renders - this helps avoid extra, unnecessary re-renders.

Prop drilling happens when you have to pass a prop through many components, just so it can reach one that’s deep in the tree.

App -> A -> B -> C -> D

Common issues:

  • It makes your component code longer and messier than it needs to be.
  • It gets harder to maintain as your component tree grows bigger.

In React, it’s better to build components by combining them together (this is called composition) rather than using inheritance like in traditional object-oriented programming.

function Layout({ header, content }) {
return (
<div>
{header}
{content}
</div>
);
}

A render prop is when you pass a function as a prop, and that function controls what gets rendered.

function DataProvider({ render }) {
const data = "Hello";
return render(data);
}
<DataProvider render={(data) => <h1>{data}</h1>} />

An HOC (Higher-Order Component) is a function that takes in a component and gives back a new, improved version of it.

function withLogger(Component) {
return function Wrapped(props) {
console.log(props);
return <Component {...props} />;
};
}

PropTypes is an older tool, but it’s still useful for checking that props have the right type while your app is running, in plain JavaScript React projects.

import PropTypes from "prop-types";
User.propTypes = {
name: PropTypes.string,
age: PropTypes.number,
};
props.name = "Hack"; // Wrong

If a component has too many props, it becomes hard to understand how to use it.

Try not to pass along data that a component doesn’t actually need.

React checks props using a “shallow” comparison, especially in memoized components (components that skip re-rendering if nothing important changed).

Old props vs New props

This means objects and arrays are compared by reference (basically, are they the exact same object in memory), not by checking everything inside them.

<User data={{ name: "Sahil" }} />

This creates a brand new object every time the component renders, which can cause re-renders that you could have avoided.

React.PureComponent automatically does a shallow comparison of props and state, so it can skip re-renders that aren’t actually necessary.

class User extends React.PureComponent {}

When a parent component re-renders, it creates new props for its children. React then compares (this step is called “reconciliation”) the child components with these new props, and updates the actual webpage (the DOM) only if something really needs to change.

graph TD A["Parent Re-renders"] --> B["New Props Generated"] B --> C["Child Receives Props"] C --> D["Reconciliation"] D --> E["DOM Updated If Needed"]

Keep these two ideas in mind:

Props = Configuration of a Component
Component = Function(props) -> UI