React is one of my favorite tech in the wide world of software engineering. It's a great JavaScript library for building user interfaces.
Yet, when I think about React, there is always one little thing that comes to my mind. And that's not related to UI or even JavaScript. It's something that I find much more precious, and much more awesome.
Let me explain.
π Divide and conquer
When you start a front-end project, you have so much work to do. Even the simplest UI has many elements in its layout. Usually, you'll have a header, a navigation, the main content and a footer. Each of these parts are also divided in many elements.
Let's take the example of an e-commerce product page. In the main content, you'll have some detailed informations about the product, about the delivery, maybe some reviews and some related products. Again, if you dive into the product details, you'll have a title, a price, a description, some pictures, an "add to cart" button, maybe an input for quantity or some dropdown menus for size and color. There is so much things to tell about a product.
The fact is: you can't avoid complexity.
You can't avoid it, but you can divide and conquer.
Let's see how to break it down.
Most frameworks or CMS implement template engines, preprocessors or builders, like Pug, Sass or Webpack, so developers can easily manage complex pages. Typically, you'll have many template files for generating a complete HTML page. In addition to that, many JS and CSS files too. You'll end up with something like this:
ββ front
ββ templates
ββ product.pug
ββ product-details.pug
ββ product-thumbnails.pug
ββ product-reviews.pug
ββ β¦
ββ js
ββ product-details.js
ββ product-thumbnails.js
ββ product-reviews.js
ββ β¦
ββ css
ββ product-details.scss
ββ product-thumbnails.scss
ββ product-reviews.scss
ββ β¦
Nice! By splitting a page into many files, each file will be shortβusually less than 100 lines, and focused on one element of the page. Content (html), style (css) and interactions (js) are well separated. I was very happy with this architectureβ¦
β¦until React came in, with the idea of Components.
π The real separation of concerns
I'm not going to lie, when I first saw a piece of code using React, I hated it. Under my eyes, something like this:
render() {
const foo = "bar";
return (
<div style={{ color: "#777" }}>
<div>{foo}</div>
</div>
);
}
HTML and CSS inside JavaScript! This was against everything I learned before. Separate content, style and interactions is the true way to be organized. Or is it?
Back to our e-commerce example. If I ask someone who is not a developer how to split the page, will she tell me to separate content, style and interactions? Of course not, she will tell me that there is a block for informations, a block for thumbnails, and a block displaying reviews. When you forget abour code, it makes more sense to divide by functionality.
OK, OK, let's do this.
ββ front
ββ product
ββ product.pug
ββ infos
ββ product-details.pug
ββ product-details.js
ββ product-details.scss
ββ thumbnails
ββ product-thumbnails.pug
ββ product-thumbnails.js
ββ product-thumbnails.scss
ββ reviews
ββ product-reviews.pug
ββ product-reviews.js
ββ product-reviews.scss
ββ β¦
ββ β¦
Not bad, huh? If I work on a feature, I have every files I need at hand.
Of course, it gets tricky if one piece can modify another. For example, you might want to change the displayed picture in the Thumbnails section, when you select a variation of a product in the Details section. OK, you don't really have every needed files at hand after all⦠But still, it's cleaner, as the file structure corresponds to the business logic, no longer to the implementation details.
Back to React: with its concept of component, a React app can be even more straightforward. Content, style and interactions in the same place is actually very convenient. We can split our product page in components, and for example adopt a simple pattern: one file = one component. It would look like this:
ββ front
ββ Product
ββ index.jsx
ββ Infos.jsx
ββ Thumbnails.jsx
ββ Reviews.jsx
ββ β¦
ββ β¦
So much better, isn't it?
And that's just the tip of the iceberg of what React can bring us.
Reasoning like this is the foundation of a very powerful practice called Domain-Driven Design. A logical and quite natural approach when working with the React library.
π One step further: composition
With an ordinary template engine, you have to include or use some inheritance strategy in order to build the whole page. For example, you have to use include
, extends
or block
keywords in Pug.
In React, you just have to use components. Contrary to what I thought at first glance, it's not "HTML in JavaScript". It's JSX. And it's wonderful! It's a way to compose functions, with the simplicity of an XML tree. A familiar syntax, since every web developer has written HTML at some point in their carrier.
const Product = () => (
<article>
<h1>My awesome product</h1>
<Details />
<Thumbnails />
<Reviews />
</article>
);
But it does not have to be flat. Maybe Thumbnails and Reviews are part of the products details. With a template engine, it can be tricky when you want a complex imbrication: the Product template includes Details, and Details includes Thumbnails and Reviews. You have to take a look at each file to understand what is going on.
With JSX and the ability to compose allow us to not fall into the same pitfall:
const Product = () => (
<article>
<h1>My awesome product</h1>
<Details>
<Thumbnails />
<Reviews />
</Details>
</article>
);
If you want to read more about this, the venerable Kent C. Dodds wrote a interesting article on that matter: One React mistake that's slowing you down.
βοΈ The right amount of abstraction
With React, you can have just the right abstraction you need. Not too much to hide implementation details, just enough to understand how things are connected together.
Not too much details, because <Reviews />
might be just a Review.jsx
file. But you might also have more than one file, say for example Review/index.jsx
+ Review/style.jsx
+ Review/fetchData.js
. Either way, you can throw this component wherever you like, and it will just work.
But enough details, so you can understand how things are connected. Above, we took the example of a feature: selecting a variant of the product must modify the displayed picture. The Details component need the value and a way to change it. The Thumbnails component also need this value to change photo when it changes.
OK then:
const Product = () => {
const [variant, setVariant] = useState();
return (
<article>
<h1>My awesome product</h1>
<Details variant={variant} onVariantChange={setVariant}>
<Thumbnails variant={variant} />
<Reviews />
</Details>
</article>
);
};
Even without knowing how Details and Thumbnails are implemented, you can make an educated guess. Our code is intuitive! That is the React's strength I love the most π
π€ Final thoughts
The Component Pattern is not unique to React. This pattern can be found in other front-end frameworks such as Angular or Vue. But it's also becoming a standard in JavaScript, with Web Components.
This idea even resonates outside the JavaScript ecosystem. Blade, the template engine of the famous PHP framework Laravel, offers the possibility to use Components. With the same objective in mind, the ability to compose pieces of code more easily. As always, some won't like it. But that's the beauty of open-source innovations: if you don't like it, just don't use it.
Happy Components to all! π