React applications are built by composing small, reusable units called components. When you "think in React," you are breaking down the UI into manageable components that each handle a single responsibility.
Imagine building a car. Instead of creating the entire car as one single piece, you break it down into smaller parts—wheels, engine, doors—each with its own specific function. React components work the same way, making your code more modular, maintainable, and reusable.
In React, a component is simply a JavaScript function that returns a React element. A component can represent a section of a webpage, a button, or even an entire navigation bar.
Let’s analyze a simple pet detail page and break it down into components:
We start with the entire page, which contains:
The navigation bar appears on every page, making it an ideal candidate for a reusable component.
// Navigation.jsx
function Navigation() {
return (
<nav>
<h1>Petrack</h1>
<a href="/pets">Pets</a>
<a href="/owners">Owners</a>
<a href="javascript:history.back()">Back</a>
</nav>
);
}
export default Navigation;
Since navigation remains constant across pages, this component adheres to the Single Responsibility Principle by handling just the navigation.
The main content of the page displays pet details and owner links. Initially, you might create a single PetDetail component, but this would mix too many responsibilities together.
// PetDetail.jsx
function PetDetail(props) {
return (
<section>
<h2>Details</h2>
{/* Pet details here */}
<h2>Owners</h2>
{/* Owner links here */}
</section>
);
}
export default PetDetail;
This component is doing too much—it should be split into smaller components.
To follow best practices, we should divide the pet details and owners list into their own components.
The pet details are structured in a table, with repeated rows. Instead of writing each row manually, we can create a reusable component.
// PetInformationItem.jsx
function PetInformationItem({ label, value }) {
return (
<tr>
<td><strong>{label}:</strong></td>
<td>{value}</td>
</tr>
);
}
export default PetInformationItem;
This component can now be used multiple times within the pet details section, making the code cleaner and more maintainable.
The owners section consists of repeated links to different owners. Instead of writing each link separately, we can create a reusable OwnerLink component.
// OwnerLink.jsx
function OwnerLink({ name, id }) {
return <li><a href={`/owners/${id}`}>{name}</a></li>;
}
export default OwnerLink;
Now, we can use OwnerLink to display multiple owner links without repeating code.
Now that we have PetInformationItem and OwnerLink, we can compose them inside larger components.
This component manages the owners section and uses the OwnerLink component.
// OwnersList.jsx
import OwnerLink from './OwnerLink';
function OwnersList({ owners }) {
return (
<section>
<h2>Owners</h2>
<ul>
{owners.map(owner => (
<OwnerLink key={owner.id} name={owner.name} id={owner.id} />
))}
</ul>
</section>
);
}
export default OwnersList;
Now that we have individual components, our PetDetail component becomes much cleaner:
// PetDetail.jsx
import PetInformationItem from './PetInformationItem';
import OwnersList from './OwnersList';
function PetDetail({ pet, owners }) {
return (
<section>
<h2>Details</h2>
<table>
<tbody>
<PetInformationItem label="Name" value={pet.name} />
<PetInformationItem label="Breed" value={pet.breed} />
<PetInformationItem label="Age" value={pet.age} />
</tbody>
</table>
<OwnersList owners={owners} />
</section>
);
}
export default PetDetail;
Each component now has a clear responsibility, making the code easier to maintain.
The final step is to wrap everything inside a PetDetailPage component.
// PetDetailPage.jsx
import Navigation from './Navigation';
import PetDetail from './PetDetail';
function PetDetailPage({ pet, owners }) {
return (
<div>
<Navigation />
<PetDetail pet={pet} owners={owners} />
</div>
);
}
export default PetDetailPage;
The PetDetailPage component serves as the root component that combines everything together.
By breaking the UI into components, we get the following hierarchy: