Components, Props, and Composition
Explore the fundamentals of React component architecture by learning to build functional components, pass data via props, and compose complex user interfaces. Understand how organizing UI as modular pieces improves code maintainability and scalability in React applications.
When we build user interfaces without structure, everything quickly becomes difficult to manage. A single large UI becomes hard to read, update, and scale. React solves this by encouraging us to break the UI into smaller, independent pieces called components.
Instead of thinking about the UI as one large structure, we divide it into parts that can be developed, reused, and maintained separately. This leads to an important shift:
We do not build pages. We build systems of components.
Creating functional components
In modern React, components are created using functions. A functional component takes input and returns JSX. For example:
function Welcome() {return <h1>Hello, world</h1>;}
This function does not directly create DOM elements. Instead, it returns a description of what should be rendered. When React renders this component, it executes the function and uses the returned JSX to update the UI. This leads to a key idea:
A component is a function that returns UI based on input.
Components as functions
Since components are just functions, they follow the same principles as JavaScript functions. They can accept inputs, return values, and be reused in different parts of the application.
function Message() {return <p>This is a reusable component</p>;}
The above component can be used multiple times across the application. Each time it is used, React calls the function again and generates a new UI description.
What are props?
Components become more powerful when they can receive data. In React, this data is passed through props. Props are inputs to a component, similar to parameters in a function.
function Greeting(props) {return <h1>Hello, {props.name}</h1>;}
The component can now render different outputs depending on the data it receives.
<Greeting name="Alice" /><Greeting name="Bob" />
Each usage produces a different result based on the provided data.
Passing data via props
Props allow data to flow from parent components to child components. This creates a predictable and structured data flow.
function App() {return <Greeting name="John" />;}
In the above example, App passes data to Greeting, and Greeting uses that data to render the UI. Props are read-only. A component should not modify its props. Instead, it should use them to determine what to render.
Component composition
One of the most powerful features of React is composition. Instead of building large components, smaller components are combined together to create complex interfaces.
function Header() {return <h1>My App</h1>;}function Content() {return <p>Welcome to the app</p>;}function App() {return (<div><Header /><Content /></div>);}
Here, the UI is built by combining smaller components. This leads to an important idea:
UI is composed like Lego blocks, small pieces combined to form larger structures.
Composing UI like LEGO blocks
Composition allows building complex interfaces by assembling simple components. Each component has a single responsibility, making the code easier to maintain and extend. Instead of writing one large component, multiple smaller components are combined to create a scalable structure. This approach improves readability and makes applications easier to manage as they grow.
Import, export, and code organization
As applications grow, components are organized into separate files. This keeps the codebase clean and maintainable. A component is typically exported from one file and imported into another. For example, a simple button component can be defined and exported like this:
export default function Button() {return <button>Click me</button>;}
This exported component can then be imported and used in other parts of the application, making the code more modular and easier to manage.
import Button from "./Button";function App() {return <Button />;}
This modular structure helps organize components logically and promotes reuse across the application. A common pattern is to group related components inside a folder. Each component lives in its own file, making it easier to manage and scale the project. As the application grows, this structure helps maintain clarity and separation of concerns.