React Component Composition: Props, Children, State and Context
React component composition means building interfaces by combining small components and deciding how they share data. Use props for explicit inputs, children for content placed inside a component, state for data that changes over time, and context for values many descendants need; composition is the design approach that helps these tools fit together.
What component composition means
A React component is a reusable unit of UI, often a function that returns JSX. Composition means assembling components inside other components rather than relying on a single large component or a rigid inheritance hierarchy. A page might combine a navigation bar, a profile panel, and a list, while each of those components combines smaller pieces.
Each component can have a focused responsibility: display data, respond to an interaction, or provide a layout. Composition does not itself decide where data lives. Props, children, state, and context are mechanisms for expressing relationships and data flow between the pieces.
Props: explicit inputs from a parent
Props are values a parent passes to a child. They make a component’s dependencies visible at the point where it is used:
function Greeting({ name }) {
return <p>Hello, {name}</p>;
}
function App() {
return <Greeting name="Mina" />;
}
In this example, Greeting receives a name and renders it. Props can be strings, numbers, objects, arrays, functions, or React elements. A callback prop lets a child request that its parent respond to an event, such as a button click.
Treat props as read-only inputs: a component should not change the props it receives. If a value needs to change, its owner should update it and pass the new value down. This one-way flow makes it easier to trace where displayed data comes from.
Children: compose content inside a component
The special children prop contains whatever JSX is nested between a component’s opening and closing tags. It is useful when a component provides a reusable frame but should not dictate all of its contents:
function Panel({ title, children }) {
return (
<section className="panel">
<h2>{title}</h2>
<div>{children}</div>
</section>
);
}
<Panel title="Account">
<p>Manage your settings here.</p>
</Panel>
Children are not limited to plain text: they can include elements, component instances, or multiple nodes. A layout component can therefore define spacing and structure while its caller chooses the specific content. For more complex layouts, named props can accept elements for particular positions, such as header and footer.
State: data that changes over time
State is a component’s changeable data, such as whether a menu is open or which filter is selected. In a function component, the useState Hook provides a value and a setter:
function Counter() {
const [count, setCount] = React.useState(0);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
Calling the setter schedules a render with the updated value; it does not directly modify the existing state variable. When the next value depends on the previous one, use the updater form, such as setCount(current => current + 1), which avoids relying on a potentially outdated value.
State should generally live in the closest common ancestor that needs to coordinate it. If two sibling components must show the same selected item, move that state to their parent and pass the value and an update callback down. This is often called lifting state up. Avoid storing a second copy of a value that can be calculated from existing props or state, because copies can drift out of sync.
Context: share values across a subtree
Context lets a component make a value available to descendants without passing it as a prop through every intermediate component. It can suit a theme, locale, or current-user information when many components in a subtree need access.
const ThemeContext = React.createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = React.useContext(ThemeContext);
return <div className={theme}>Tools</div>;
}
The provider supplies a value, and a descendant reads the nearest matching provider’s value. Context avoids repetitive forwarding, sometimes called prop drilling, but it also makes a component’s dependency less obvious from its props. Use it for genuinely shared subtree data, not as an automatic replacement for every prop.
How to choose the right approach
- Choose props when a parent supplies a specific value or callback to a child. This is usually the clearest default.
- Choose children when a component should wrap or position caller-provided content without controlling its exact details.
- Choose state when a value changes in response to interaction or other events. Keep it near the components that own or coordinate that change.
- Choose context when many descendants need the same value and passing it through intermediate components would add noise.
- Combine them when appropriate: state may live in a provider’s parent, context may distribute it, and a component may use children to define its layout.
For example, a settings screen could keep the selected theme in state, pass it as a prop to a small preview, and use context to make it available to several deeply nested controls. The choice depends on who needs the value and who is responsible for changing it, not on a rule that one mechanism is always best.
Common problems and useful distinctions
A frequent misconception is that children and props are alternatives. Children are a kind of prop: JSX nested inside a component is made available through the children property. A component can accept both children and named props.
Another common problem is placing all state at the top of an application. This can make data flow harder to follow and cause unrelated parts of the interface to depend on the same owner. Lift state only as far as needed. Conversely, duplicating state in several siblings creates synchronization work; prefer one owner and pass values or callbacks.
Context can also be overused. A component that reads context is coupled to that context’s provider and may be less reusable in isolation. If only one child needs a value, a prop is often simpler. If you use context for frequently changing values, consider how many consumers need to update when the value changes; separating unrelated context values can make dependencies clearer.
Composition is not a performance trick by itself. React renders components according to changes in their inputs and state, and unnecessary optimization can make code harder to maintain. First make ownership and data flow understandable; optimize only when there is a measured need.
Frequently Asked Questions
What is the difference between props and state in React?
Props are inputs received from a parent, while state is data a component (or its owner) updates over time. A parent can pass its state to a child as props.
Is children a special prop in React?
Yes. JSX placed between a component’s tags is passed as its children prop, allowing the component to wrap or arrange that content.
When should I use context instead of props?
Use context when a value is needed by many descendants and forwarding it through intermediate components would be cumbersome. Prefer props when the relationship is local and explicit.
Should state always stay in the component that uses it?
No. Keep state local when possible, but move it to a common ancestor when multiple components need to coordinate or display the same changing value.
Does React composition replace component inheritance?
Composition is the usual way to reuse and combine React UI: components accept props and render other components or children. It does not mean every possible use of inheritance is technically impossible, but inheritance is not needed for ordinary UI composition.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.