Taking decisions to structure big projects with Hooks, Stores, Services and more…
Nowadays there are a lot of different tools to work with components, some of them help us to decrease the coupling between our code, others help us to have a better communication and some others give us a better DOM performance or teach us how to structure our files.
Choosing a files naming convention
The naming convention will help you a lot when you have to create a project with a lot of components, remember that we always want a more maintainable, scalable and extensible structure when we create new and long-term projects.
Spoiler: To use a folder called ‘components’ and add all the components inside, is not going to be the best practise.
The real important thing here is that has to be maintainable and if others join your project, have to be able to understand it.
Talking about naming convention there are at least these basic conventions:
- PascalCase aka TheElder: This convention is really usual in Backend scenarios, and to name the components in Frontend.
- camelCase aka theCommon: Probably the most used convention in the Frontend side.
- kebab-case aka the-modern: The popularity of this convention has increased recently, with frameworks like Angular.
- sneak_case aka dont_use_this: Not really used convention.
Which is the best? None of them and all of them, choose one you like. And Which I prefer? Personally I really like the naming convention that was introduced some years ago.
They use kebab-case and also add the type of the file to the name, that means that we can have some names like this:
But from some time ago, the community accepted to use PascalCase ONLY for Components, that means that in the case of the component you will see something like Home.js
Structuring Files and Folders
About this convention, there are two big ways to structure the files and folders:
- Folder-by-type: In this case you group the files depending on their type, for example the famous folders called “components” or “services”.
- Folder-by-feature: On the other hand grouping the files by feature, means that you will have different type of files in the same folder, for example “home” or “home-input” can be your folders.
I like to do a mix of that two kind of structuring, by default I use by-feature but if the project is not so big (How can I know if my project is big?), I can by-type for some parts of it, for example “helpers”.
Again, a good example is this style guide where they also give us some other interesting conventions like, but there are other similar that can help you:
- One folder per module: A module is a group of features, usually can be a page, but can have some other pages in it. “home”, “blog”, “products”.
- Use shared folder: When you want to share something from the level where is created to the siblings or children, move it to a folder called shared, this will help to know what is shared. Remember that you can create a lot of shared folders.
- Core could useful: A special case for shared folder can be core folder, is a shared folder with really core things of the project, and usually there is only one per project.
The layers that we have to work with components in our projects
Frontend is constantly evolving, and we always want to use the new-cool-amazing think that have appeared the last week. But do I need it?
The short answer is: Nope 🙅🏻♀️
The useful answer is: Depending on your necessities and what are your component, and your project doing 🤙🏽
I try (and sometimes fail) to follow this simple rule:
If you are not sure if you need a layer, you don’t need that layer.
Nowadays, the Component is the basic piece in all our projects, as how the official web components website define:
Web components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps
In the simplest Component, you will probably only need the Component, and nothing else, sometimes that components are called Pure Components or Stateless Components.
In that kind of Components for the same props you will always return / render the same result. In these components you don’t need State, Hooks, Complex Services, etc.
When the component starts to grow, there are new layers that we can use, for example Hooks, that are one of the newest tools in the Frontend scenarios, and could be really helpful. If you have never listened about Hooks, you can start with Dan Abramov video about Hooks, React was the first Framework to introduce Hooks but is probably going to be extended to other frameworks.
First, we can use Hooks in our component, but we can also create our own Hooks and move some responsibility of the Component to the Hook, but why? Because you want to share this logic between Components.
Is important to remember that Hooks and Components share their life-cycle this makes that Hooks and Component are really close parts of our project.
When you need to do some operations in different parts of your app, but these operations are agnostic to your data (you can use them on other projects without changes) could be a good idea to move this data to Helpers (also known as Utils).
The idea behind a Helper is that has to be like a library, for example you can create helpers to conversion between data, clone objects deeply, etc. Libraries like jQuery, moment or lodash are examples of Helpers.
Ok, but sometime you need more than only functions that return results from different parameters, when Helpers are not enough, Services will help you a lot, this kind of files are more complex than Helpers and can create their own context, keep data in memory, be Singleton or Transient etc.
The easiest way to see the difference between a Helper and a Service is that if you want to create a class and an instance of that class, you probably want a Service, but if you want only to call some functions and receive a result, Helpers will help you more than Services.
And what happens when I want to share data between components? Stores will help you a lot on this, (No idea of what is a Store? Check this article).
When local state is not enough we can move the State to a Store, by design the Store is global but has different Modules. When you need a store in a component you can import or inject some of that modules.
An interesting structure of Store Modules is represented in NgRx where they implement a module for each feature.
How to connect all these layers?
If you have all the layers, is important to follow some instructions, after try in different projects this is the way that I prefer.
The Component interacts with a Hook, this Hook could be used in one or more components.
The Hook interacts with other Hooks, Services and Stores.
A Service can call to other Services and is called by other Services and Hooks.
Finally, Stores are called by Hooks and when the state is updated this could be directly reflected to the Component via the Hook.
And Helpers? Easy, everybody can use Helpers 🎉
But, in the most cases you DON’T need all the layers, usually you will have one layer, and will add another layer because you REALLY need that new layer, and after this another, etc.
In that case you can avoid some layers, but respecting what I wrote some lines above.
For example, a Component can directly call a Service, but if this happens is because this Component does not have a Hook.
The same with a Store, could be called directly from the Component, but probably is not a good idea to:
- Call a Store from a Service.
- Call a Hook from a Service.
- Call a Store from a Helper.
Note: Sometimes we have big Services that interact with APIs for that cases is interesting to have a Hook that connects this Service with other Hooks or Components. On that case is not a good idea to call from a Hook to that Service that has this Hook-Connector.
And you? Do you have more scenarios and techniques to structure your project based on Components? Tell me more about what do you think and how you create your projects.