Just like Modularity in OOP (Object Oriented Programming) is an important concept used in dividing or decomposing a program into subsets (loosely coupled modules) so as to make it less complex and perhaps reusing the modules whenever they can be used, in this tutorial, we will take an example to convert a fully written Component of React into couple of modules.
The end result will be, both the non-modularized and the modularized code that will work to conclude the same result.
Requirements
1) Basic React and JS/X introductory knowledge.
2) A CodePen account (It's free to create and use).
So let's start working on it!
Below, we have a non-modularized code, its components are not independent and that is our job to make it so.
function VideoGame(props) {
return (
<div id="Title">
<div id="Genre">
<div id="Price">
<img
id="thumbnail"
src={props.game.thumbnailUrl}
alt={props.game.thumbnailText}
/>
<div id="user-rating">{props.game.rating}</div>
</div>
</div>
<div id="user-comments">{props.game.comments}</div>
<div id="comment-date">{props.game.date}</div>
</div>
);
}
Question - Why do we need to modularize?
To make smaller and single-responsibility pieces because they are easier to reuse and debug, and more importantly, a maintainable chunk of code that you won't be overwhelmed by looking at it, in the near future.
Step 1: Quiz Time!
Extract the natural components that you can think of from the above code.
Once done, you can look at the answer below:
• Thumbnail (image)
• Rating
• Comment text
• Comment date
• Container wrapper (Genre/Price)
Step 2: Extract the natural components.
function Thumbnail({ src, alt }) {
return <img id="thumbnail" src={src} alt={alt} />;
}
function UserRating({ rating }) {
return <div id="user-rating">{rating}</div>;
}
function UserComments({ children }) {
return <div id="user-comments">{children}</div>;
}
function CommentDate({ date }) {
return <div id="comment-date">{date}</div>;
}
So, each of the component above is independently reusable, such is the benefit of a modular design.
Step 3: Glue them components!
As it is always easy and better to build something piece-by-piece.
function HeaderFrame({ children }) {
// Keeps the existing layout structure (Title > Genre > Price)
return (
<div id="Title">
<div id="Genre">
<div id="Price">{children}</div>
</div>
</div>
);
}
function VideoGame(props) {
const { game } = props;
return (
<>
<HeaderFrame>
<Thumbnail src={game.thumbnailUrl} alt={game.thumbnailText} />
<UserRating rating={game.rating} />
</HeaderFrame>
<UserComments>{game.comments}</UserComments>
<CommentDate date={game.date} />
</>
);
}
Full code
(You can just copy-paste it into the HTML tab of CodePen):
<html>
<head>
<meta charset="utf-8" />
<title>React Before vs After</title>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<style>
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial; margin: 20px; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.panel { border: 1px solid #ddd; border-radius: 10px; padding: 12px; }
h3 { margin: 0 0 8px; font-size: 16px; }
#Title { border: 1px solid #ccc; padding: 8px; border-radius: 8px; }
#Genre { border: 1px dashed #bbb; padding: 6px; border-radius: 6px; }
#Price { border: 1px dotted #aaa; padding: 6px; border-radius: 6px; display: flex; gap: 10px; align-items: center; }
#thumbnail { width: 120px; height: 80px; object-fit: cover; border-radius: 6px; }
#user-rating { font-weight: 700; }
#user-comments { margin-top: 8px; white-space: pre-wrap; }
#comment-date { margin-top: 6px; color: #666; font-size: 0.9em; }
</style>
</head>
<body>
<div class="grid">
<div class="panel">
<h3>Before (Single Component)</h3>
<div id="root-before"></div>
</div>
<div class="panel">
<h3>After (Modular Components)</h3>
<div id="root-after"></div>
</div>
</div>
<script type="text/babel">
const { createRoot } = ReactDOM;
const game = {
thumbnailUrl: "https://via.placeholder.com/120x80?text=Game",
thumbnailText: "Game thumbnail",
rating: "★★★★☆",
comments: "Great gameplay and soundtrack.\nWorth a replay!",
date: "2023-11-05"
};
// A) Before modularization
function VideoGameBefore(props) {
const { game } = props;
return (
<div id="Title">
<div id="Genre">
<div id="Price">
<img id="thumbnail" src={game.thumbnailUrl} alt={game.thumbnailText} />
<div id="user-rating">{game.rating}</div>
</div>
</div>
<div id="user-comments">{game.comments}</div>
<div id="comment-date">{game.date}</div>
</div>
);
}
// B) After modularization
function Thumbnail({ src, alt }) {
return <img id="thumbnail" src={src} alt={alt} />;
}
function UserRating({ rating }) {
return <div id="user-rating">{rating}</div>;
}
function UserComments({ children }) {
return <div id="user-comments">{children}</div>;
}
function CommentDate({ date }) {
return <div id="comment-date">{date}</div>;
}
function HeaderFrame({ children }) {
return (
<div id="Title">
<div id="Genre">
<div id="Price">{children}</div>
</div>
</div>
);
}
function VideoGameAfter({ game }) {
return (
<>
<HeaderFrame>
<Thumbnail src={game.thumbnailUrl} alt={game.thumbnailText} />
<UserRating rating={game.rating} />
</HeaderFrame>
<UserComments>{game.comments}</UserComments>
<CommentDate date={game.date} />
</>
);
}
createRoot(document.getElementById("root-before")).render(
<VideoGameBefore game={game} />
);
createRoot(document.getElementById("root-after")).render(
<VideoGameAfter game={game} />
);
</script>
</body>
</html>
Well, that covers it!
I hope you had a good time and thank you reading for the article.
We tried to understand how modularity can help you being more efficient by working iteratively, with feedback as you go!