The design of every web Application should be driven by its navigation and URL structure. The URL map should be strictly defined beforehand and, alongside the sitemap; should:
- provide clear understanding of the application structure by everyone on the team and not only by developers (as usually happens, because only they have access to the codebase where URLs are defined), i.e. stakeholders, developers, designers and QAs;
- prevent inconsistencies and mistakes in UX in early stages of development;
- help in requirements elicitation;
- act as documentation (which will greatly improve the overall experience for newcomers);
- provide understanding of what should be implemented in the back-end application, as client application usually dictates the shape of data to be consumed
Besides correctly designing the URL structure, one of the hardest aspects of building any React application (and programming in general) is naming the Components and correctly namespacing them. Without a system you would end up with huge Component names like AdminUsersProductFilteredReportList. Not only this is incomprehensible, but also hard to maintain and compose.
Considering all of the above, we believe that naming conventions should closely relate to the URL structure. After we’d completed a dozen or so React applications we came to the Ryan Florence’s approach, but with a few modifications.
Categories of URLs
Let’s start with terminology defining different categories of URLs:
- Empty namespace /
- Namespaced, e.g /admin
- Collection URL, e.g. /admin/posts, /comments
- Resource URL, e.g. /admin/post, /profile, /admin/dashboard
- Action URL, e.g. /admin/posts/new, /users/login, /posts/123/edit, which could be considered as a special case of resource URL
In order to understand everything more clearly, imagine an application with the following URL structure:
The folder structure for this URL mapping would look like this:
There are a couple of interesting points to highlight.
- The folder structure mirrors the URL structure.
- You don’t need to come up with sophisticated names, you just name and nest them according to URLs — very simple rule to follow.
- No name collisions, folders act as namespaces and you can have as many `Users` components as you want as long as they are placed on different levels.
But the most important point is that the folders placed on the same level are completely independent of each other. Dashboard and its children could be easily modified or removed without affecting Profile. Basically, you have independent applications so long as you don’t share components between them.
Let’s move on and see how the applications is structured when we collapse the folders:
Every folder has index.js file, with the purpose is to re-export the components inside the folder. Re-exporting is done according to the following rules:
If it is a folder that corresponds to a namespaced URL, export its descendant components with an asterisk notation.
E.g. Dashboard/index.js would look:
And then in your routes you can write:
As you can see, even if you don’t specify a FQN (Fully Qualified Name) it’s possible to still not lose the semantics.
If it’s a folder that corresponds to a non-namespaced component export it without an asterisk.
Scene component and routing
Every folder that corresponds to a collection, resource or action URL has Scene.js file, which purpose is to be a component provided in routes configuration as a RouteHandler. This means that every folder without a Scene.js automatically indicates a namespaced URL, e.g. `Dashboard` and `Users` components. Here’s how the routes declaration will look using ReactRouter v3:
The example of Scene.js for /dashboard/activity URL:
The idea of the Scene component lies not only in providing a unified approach to structuring an application, but also in a more granular configuration.
For example, a common requirement is that URLs nested under the same namespace could have different layouts, so forcing a layouting on the routing level will result in less flexibility, which means it’s better to apply them on a component level. That’s where the Scene component comes in handy. You can easily define a Layout component for a specific URL and wrap it inside a Scene component. This is how our Dashboard/Activity/Scene.js would change after applying a Layout:
Notice that Layout is defined on the same level as the Activity component itself, indicating its relationship. By going away from defining the layouts in the static routes configuration we make the routes configuration less noisy and provide more flexibility on component level, i.e. you can control the rendering of layouts by passing props.
With ReactRouter v4 it’s slightly different since it advocates a dynamic routing configuration as opposed to a static one meaning there is no central routing configuration. Routes are defined on a component level and are components themselves. Here’s how it would look like:
And here is the code for the Dashboard.Scene. In this case even for namespaced URL components we need Scene.js:
Complete workflow for starting a new React application
Assuming you have UX/UI wireframes developed beforehand (e.g. using balsamiq):
- Start by defining the sitemap of the application. You can use http://ux.ant.design.
- Focus on the flow of the application, not on the contents of the page. Each block doesn’t necessarily correspond to a separate page.
- Assign URL to each block.
- Define URL structure as detailed as possible using a sitemap. (The result should be similar to this). Include query and hash parameters, if you know them at this phase. For example, including ?page=1 parameter is common for collection URLs. This would help in planning for API requirements.
- Setup the project (this can be done in parallel with the previous steps).
- Create a folder structure inside /scenes folder according to a URL structure.
- Define routes (only for RRv3): define static routes as described in this example. For RRv4 there is no need to define routes at this stage as routes are simple components reacting to current URL and you can gradually add them as you develop an application.
- Identify how many layouts and to which URLs should they correspond.
- Develop layouts using https://ant.design/components/layout and https://ant.design/components/grid. At this phase, you’re not aiming to produce a complete working layout with Header, Sidebar, Footer or whatever your layout is comprised from, those could and should be done at a later stage — you should only focus on component positioning and hierarchy.
- With layouts defined and implemented it’s time to start implementing the application UI logic. Use https://ant.design/docs/react/introduce as a UI kit for common components. If you need to override them, place the overridden components inside /scenes/components.
We understand that this approach is rather opinionated, but it works for our team and enables parallel development, because having precise naming conventions and a structured approach makes it easy to provide better communication between developers about the application features and to expedite the onboarding of new developers.
How To Properly Structure Your React Applications was originally published in JetRuby on Medium, where people are continuing the conversation by highlighting and responding to this story.
This post first appeared on JetRuby Agency - Featured Technical Stories Based In Our Experience, please read the originial post: here