There is very little guidance on how to organize front-end applications in the world of React. (Just move files around until it “feels right,” lol). The truth is that we can do better. Let’s take a look at one pattern you might consider using to architect your site.
At first, you might split up your code between /components and /containers folders. This works for small sites but you’ll find yourself look for something more robust when scaling to larger sites. Luckily, decades of research into systems design has given us a wealth of patterns to explore to create a scalable architecture.
One of those is domain-driven design, and it has regained popularity over the last few years. Let’s explore how we can use it in React-land.
A primer on domain-driven design
Domain-driven design (DDD) is the practice of managing complexity of software applications by relating their underlying data models to domain logic. That’s a mouthful, so let’s break it down further.
The domain is an ontology, meaning how things are grouped in the world. For example, the word joist has a very specific connection to the domain of building construction. Another word, like Mike, can belong to multiple domains, such as the domain of Biblical names (short for Michael), or in the domain of politics as it relates to the NATO phonetic alphabet.
When the design is domain-driven, it means we place the model of our domain (e.g. a playing card in the domain of Poker) in a context (e.g. the contextual grouping, such as a Game) to help manage the complexity.
Organizing a DDD site
Domain-driven design is specifically for handling the complexity of growing sites as they add more and more models. It doesn’t really make sense for a site with one model. Once you get to about four models, that’s a good time to start looking at binding your models to multiple contexts. This isn’t a hard-and-fast rule, so don’t feel like you have to break out into multiple contexts, but once you get above four models, those contextual groupings will begin to surface.
Start by organizing your domains
Let’s use Twitter as our example site to organize. One way to separate domains within Twitter is to split up our models between the Blog platform that powers the Tweets and the Interaction elements that enable the micro-blogging to spread and flourish.
Is this the only way to separate concerns in Twitter? Definitely not! One key aspect of DDD is that there is no one correct way to create domains. There are plenty of ways to split up the bounded contexts of an application, so don’t focus too much on the architecture we’ve chosen. Instead, use this as a springboard to understand how we can apply DDD to the organization of our front-end code.
That said, our code will now be structured to look like this (assuming you start with something like create-react-app):
twitter/ ├── App.css ├── App.js ├── App.test.js ├── blog/ └── interaction/
Define the components and containers in each domain
Now that we have our basic folder structure set up, it is time to add some real components! Looking at our domain UML diagram above, it would be useful to start with containers that fetch data on a given page and components that organize the templates that compose those pages. Expanding on our app, we now have the following structure in place (omitting our accompanying test.js files for simplicity):
twitter/ ├── App.css ├── App.js ├── App.test.js ├── blog/ │ ├── HomePage.js │ ├── TweetCard.js │ ├── TweetDialog.js │ ├── TweetList.js │ ├── TweetListItem.js │ ├── UserPage.js │ └── UserCard.js └── interaction/ ├── FollowButton.js ├── LikeButton.js └── ShareButton.js
We still keep our App file to initialize React to our root-level HTML tag. With our domains in place, we begin to build our containers (such as HomePage and UserPage) and components (such as TweetCard and TweetListItem). Alternatively, we could further segment the models within our domains to look like so:
twitter/ └── blog/ ├── user/ │ ├── HomePage.js │ ├── UserCard.js │ └── UserPage.js └── tweet/ ├── TweetCard.js ├── TweetDialog.js ├── TweetList.js └── TweetListItem.js
But given the size of the application it isn’t necessary at this stage.
Add helpers, if they’re needed
As we build out our application our UIs will continue to increase in complexity. To deal with this, we have two methods for separating concerns and pulling logic out of our component templates: presenters and utilities. Presenters push all of the visual presentation logic out of the templates to keep the view layer as clean and simple as possible. Utilities collect shared functionality for all other logic on the front end that is not specifically related to the templates. Let’s examine these a bit closer.
Clean up templates with presenters
Think of a Twitter profile. What kinds of elements do you see here on my account?
There’s information directly related to my user: name, handle, description, location, website, birthday, start date. There are also counts of associations between other models — how many other users are following me? How many other users am I following? There’s additional logic that isn’t even captured on the page, such as my tweets, replies, media uploads, and content I’ve liked. To capture all of this presentational logic appropriately, we can add an additional file within our file tree to isolate our presenter pattern from the JSX component:
twitter/ └── blog/ ├── user/ │ ├── UserCard.js │ ├── UserCard.presenter.js
Push out logic into utilities
Certain presentational logic is so fundamental that it could be useful across applications regardless of whether or not it is used within rendering. Currency formatting, validations, and timestamp formatting are all use cases where we could benefit from isolated utility functions across our application. Where do those live? Since they span domains, utilities can be in their own folder:
twitter/ ├── App.css ├── App.js ├── App.test.js ├── blog/ │ ├── HomePage.js │ ├── TweetCard.js │ ├── TweetDialog.js │ ├── TweetList.js │ ├── TweetListItem.js │ ├── UserCard.js │ ├── UserCard.presenterjs │ └── UserPage.js ├── interaction/ │ ├── FollowButton.js │ ├── LikeButton.js │ └── ShareButton.js └── utils/ ├── currency.js ├── time.js └── validation.js
There is no wrong way to organize your app!
Ultimately, the choice is yours. This is just one example for myriad ways you could arrange your application. Domain-driven design is a valuable tool because it separates business logic in a meaningful way, creates a clearer distinction for domain expertise amongst developers, and provides rules for easily organizing and scaling your code.
But if you’re looking for an alternative to the traditional chaos of React application file structures, take a look at domain-driven design. It may be just the thing.
Lastly, if you like this sort of content and want to learn more about front-end, user interface development, and UX design and research (organized by your experience in the industry), I run a free newsletter that you might want to check out.
The above is the detailed content of Domain-Driven Design With React. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

There are three ways to create a CSS loading rotator: 1. Use the basic rotator of borders to achieve simple animation through HTML and CSS; 2. Use a custom rotator of multiple points to achieve the jump effect through different delay times; 3. Add a rotator in the button and switch classes through JavaScript to display the loading status. Each approach emphasizes the importance of design details such as color, size, accessibility and performance optimization to enhance the user experience.

To deal with CSS browser compatibility and prefix issues, you need to understand the differences in browser support and use vendor prefixes reasonably. 1. Understand common problems such as Flexbox and Grid support, position:sticky invalid, and animation performance is different; 2. Check CanIuse confirmation feature support status; 3. Correctly use -webkit-, -moz-, -ms-, -o- and other manufacturer prefixes; 4. It is recommended to use Autoprefixer to automatically add prefixes; 5. Install PostCSS and configure browserslist to specify the target browser; 6. Automatically handle compatibility during construction; 7. Modernizr detection features can be used for old projects; 8. No need to pursue consistency of all browsers,

Setting the style of links you have visited can improve the user experience, especially in content-intensive websites to help users navigate better. 1. Use CSS's: visited pseudo-class to define the style of the visited link, such as color changes; 2. Note that the browser only allows modification of some attributes due to privacy restrictions; 3. The color selection should be coordinated with the overall style to avoid abruptness; 4. The mobile terminal may not display this effect, and it is recommended to combine it with other visual prompts such as icon auxiliary logos.

Use the clip-path attribute of CSS to crop elements into custom shapes, such as triangles, circular notches, polygons, etc., without relying on pictures or SVGs. Its advantages include: 1. Supports a variety of basic shapes such as circle, ellipse, polygon, etc.; 2. Responsive adjustment and adaptable to mobile terminals; 3. Easy to animation, and can be combined with hover or JavaScript to achieve dynamic effects; 4. It does not affect the layout flow, and only crops the display area. Common usages are such as circular clip-path:circle (50pxatcenter) and triangle clip-path:polygon (50%0%, 100 0%, 0 0%). Notice

Themaindifferencesbetweendisplay:inline,block,andinline-blockinHTML/CSSarelayoutbehavior,spaceusage,andstylingcontrol.1.Inlineelementsflowwithtext,don’tstartonnewlines,ignorewidth/height,andonlyapplyhorizontalpadding/margins—idealforinlinetextstyling

TheCSSPaintingAPIenablesdynamicimagegenerationinCSSusingJavaScript.1.DeveloperscreateaPaintWorkletclasswithapaint()method.2.TheyregisteritviaregisterPaint().3.ThecustompaintfunctionisthenusedinCSSpropertieslikebackground-image.Thisallowsfordynamicvis

To create responsive images using CSS, it can be mainly achieved through the following methods: 1. Use max-width:100% and height:auto to allow the image to adapt to the container width while maintaining the proportion; 2. Use HTML's srcset and sizes attributes to intelligently load the image sources adapted to different screens; 3. Use object-fit and object-position to control image cropping and focus display. Together, these methods ensure that the images are presented clearly and beautifully on different devices.

Different browsers have differences in CSS parsing, resulting in inconsistent display effects, mainly including the default style difference, box model calculation method, Flexbox and Grid layout support level, and inconsistent behavior of certain CSS attributes. 1. The default style processing is inconsistent. The solution is to use CSSReset or Normalize.css to unify the initial style; 2. The box model calculation method of the old version of IE is different. It is recommended to use box-sizing:border-box in a unified manner; 3. Flexbox and Grid perform differently in edge cases or in old versions. More tests and use Autoprefixer; 4. Some CSS attribute behaviors are inconsistent. CanIuse must be consulted and downgraded.
