avatarJuan Bernal

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3212

Abstract

meComponent │ │ ├── SomeComponent<span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.tsx</span> │ │ ├── SomeComponent<span class="hljs-selector-class">.tsx</span> │ │ └── someComponent<span class="hljs-selector-class">.scss</span> │ └── index<span class="hljs-selector-class">.ts</span> ├── constants │ ├── index<span class="hljs-selector-class">.ts</span> │ └── someFeature<span class="hljs-selector-class">.ts</span> ├── containers │ ├── dashboard │ │ ├── Dashboard<span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.tsx</span> │ │ ├── Dashboard<span class="hljs-selector-class">.tsx</span> │ │ └── dashboard<span class="hljs-selector-class">.scss</span> │ └── login │ ├── Login<span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.tsx</span> │ ├── Login<span class="hljs-selector-class">.tsx</span> │ ├── components │ │ ├── SomeComponent │ │ │ ├── SomeComponent<span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.tsx</span> │ │ │ ├── SomeComponent<span class="hljs-selector-class">.tsx</span> │ │ │ └── someComponent<span class="hljs-selector-class">.scss</span> │ │ └── index<span class="hljs-selector-class">.ts</span> │ └── login<span class="hljs-selector-class">.scss</span> ├── fonts │ └── SomeFont<span class="hljs-selector-class">.ttf</span> ├── reducers │ ├── index<span class="hljs-selector-class">.ts</span> │ └── someReducer │ ├── someReducer<span class="hljs-selector-class">.test</span><span class="hljs-selector-class">.ts</span> │ └── someReducer<span class="hljs-selector-class">.ts</span> ├── styles │ ├── animations<span class="hljs-selector-class">.scss</span> │ ├── index<span class="hljs-selector-class">.scss</span> │ └── variables<span class="hljs-selector-class">.scss</span> ├── types │ ├── index<span class="hljs-selector-class">.ts</span> │ └── someFeature<span class="hljs-selector-class">.ts</span> └── utils ├── index<span class="hljs-selector-class">.ts</span> └── someUtil.ts</pre></div><h2 id="1609">Takeaways</h2><ol><li><b>Code is colocated </b>If we examine the way in which the <code>actions</code> folder or <code>reducers</code> is structured, we can quickly understand that these folders hold all of our reducers and actions, but they are in their own distinct folders. This is because, for the sake of this example, while all reducers and actions impact the app globally, they are each their own unit hence they each live in their own subfolder. They have their own tests and do a particular thing. Think of this as it might apply to a development work environment: all of the developers are under the same building (global folder), but they each adhere to their own desk, application team, or functional unit (subfolder) and they each have their own laptops, keyboards, or monitors (files).</li><li><b>Code which has a relationship with more than one other piece of code (or you can think of this as code in one file in relation to code in another file) lives at the root level </b>By doing this, we can signal to

Options

whomever picks up this code and runs with it that each of these <i>things </i>that live at the highest level trickle down in more than one place of the app. It’s not just apparent at the root level, though. If we examine what is going on within the <code>containers</code> folder (could be renamed <code>pages</code> , <code>views</code> , etc. based on your preference), we also notice that there is an encapsulation relationship taking place. There is another <code>components</code> folder living within there. Each of the components that uniquely make up that particular container is an essential feature which will only ever be used in that container and nowhere else. The relationship is apparent; if these components lived outside at the root level of the app, but were only ever used in one container, you may find yourself wondering why the folder traversal is more complex than it has to be or why it shares space with <i>things</i> that it does not have a relationship with.</li><li><b>Nesting does not have to be an issue </b>The example provides a React app file structure which has at most three levels of nesting within each global folder, useful so that you don’t get lost, but illustrates the simplicity side-effect of applying the relationship-first structure. If we <a href="https://readmedium.com/8-react-tips-tricks-1f1a429d7da0">keep our components simple</a>, our containers folder, the one which is nested the deepest, will never have to go more than three levels deep.</li><li><b>Index files are present for clean importing </b>This is honestly just a nice-to-have. If you use aliases for your imports, this may not be necessary.</li></ol><p id="f7b4">Coming up with the perfect file structure for your React project is not impossible, it just takes a bit of experimentation. The React docs also have a great bit of advice on file structure if the above seems too complex for you:</p><blockquote id="fbce"><p>If you feel completely stuck, start by keeping all files in a single folder. Eventually it will grow large enough that you will want to separate some files from the rest. By that time you’ll have enough knowledge to tell which files you edit together most often. In general, it is a good idea to keep files that often change together close to each other.¹</p></blockquote><p id="9218">If anyone ever suggests that there is only one way to approach the implementation of a file structure in a React app then they are dead wrong. File structures change from project to project and from team to team. You may find that the discussion above on developing a file structure may work, but might need a dash of experimental reasoning when it comes to your own codebase. Simply remember that an effective file structure is often reliant on being able to do the following two things in the most efficient, most elegant way possible:</p><ul><li>Folder traversal and being able to bypass the side effects of deep nesting</li><li>Reflecting impact across code (how a component or module may be used in a page or elsewhere), whether imposed by commonality or by relationship</li></ul><p id="0ec9">[1]: <a href="https://reactjs.org/docs/faq-structure.html">React docs</a></p></article></body>

Photo by Maarten van den Heuvel on Unsplash

A Simple Approach to File Structures in React Apps

The typical problem statement to file structures in React is simple: “Where does it make the most sense to put this thing?” Let’s solve this problem once and for all!

React app file structures can either be a pain and obtrusive or advantageous and modest. If you are like most developers, you’ll want to find the best approach that suits your particular app’s case. The fact that React allows you to be flexible in what you can use with it, be it the handful of packages or ways in which one can manage state, for instance, makes the file structure a somewhat tricky problem to solve.

File structures are hard regardless of the library, framework, or language. Unless there is a highly opinionated convention that should be followed like in some frameworks, you’ll have a hard settling on one structure throughout the life of an app. The concern or ongoing discussion on how to solve the structure problem can be made a thing of the past if we approach a solution to the problem by way of understanding when it is most a problem: when the relationship of the code is not obviously reflected by the file structure.

Focus on the file relationships (or colocation principle)

In looking at the problem through the lens of a team instead of the individual, begin to ask yourself what might be the biggest conflict within a team when it comes to developing a file structure. You may find that often times the reason why the file structure is difficult to come up with in a group setting is because of conflicting points of view when it comes to what goes where and how to name folders or files. Some might want all components at the root level in a folder called ‘components’. Others may opt for the use of a ‘common’ folder which houses the components in a ‘components’ folder. The variations are endless! However, if we step away from the needs or concerns of the person writing the code and take a look at the relationship within the code, we can begin to develop a file structure that just makes sense.

The approach

Let’s take a look at an example file structure that takes advantage of relationships. Note: This particular example is using Typescript and Redux for state management, but can be applied to React apps using Javascript. Simply replace the file extensions of .ts/.tsx with .js/.jsx .

.
├── actions
│   ├── index.ts
│   └── someAction
│       ├── someAction.test.ts
│       └── someAction.ts
├── components
│   ├── SomeComponent
│   │   ├── SomeComponent.test.tsx
│   │   ├── SomeComponent.tsx
│   │   └── someComponent.scss
│   └── index.ts
├── constants
│   ├── index.ts
│   └── someFeature.ts
├── containers
│   ├── dashboard
│   │   ├── Dashboard.test.tsx
│   │   ├── Dashboard.tsx
│   │   └── dashboard.scss
│   └── login
│       ├── Login.test.tsx
│       ├── Login.tsx
│       ├── components
│       │   ├── SomeComponent
│       │   │   ├── SomeComponent.test.tsx
│       │   │   ├── SomeComponent.tsx
│       │   │   └── someComponent.scss
│       │   └── index.ts
│       └── login.scss
├── fonts
│   └── SomeFont.ttf
├── reducers
│   ├── index.ts
│   └── someReducer
│       ├── someReducer.test.ts
│       └── someReducer.ts
├── styles
│   ├── animations.scss
│   ├── index.scss
│   └── variables.scss
├── types
│   ├── index.ts
│   └── someFeature.ts
└── utils
    ├── index.ts
    └── someUtil.ts

Takeaways

  1. Code is colocated If we examine the way in which the actions folder or reducers is structured, we can quickly understand that these folders hold all of our reducers and actions, but they are in their own distinct folders. This is because, for the sake of this example, while all reducers and actions impact the app globally, they are each their own unit hence they each live in their own subfolder. They have their own tests and do a particular thing. Think of this as it might apply to a development work environment: all of the developers are under the same building (global folder), but they each adhere to their own desk, application team, or functional unit (subfolder) and they each have their own laptops, keyboards, or monitors (files).
  2. Code which has a relationship with more than one other piece of code (or you can think of this as code in one file in relation to code in another file) lives at the root level By doing this, we can signal to whomever picks up this code and runs with it that each of these things that live at the highest level trickle down in more than one place of the app. It’s not just apparent at the root level, though. If we examine what is going on within the containers folder (could be renamed pages , views , etc. based on your preference), we also notice that there is an encapsulation relationship taking place. There is another components folder living within there. Each of the components that uniquely make up that particular container is an essential feature which will only ever be used in that container and nowhere else. The relationship is apparent; if these components lived outside at the root level of the app, but were only ever used in one container, you may find yourself wondering why the folder traversal is more complex than it has to be or why it shares space with things that it does not have a relationship with.
  3. Nesting does not have to be an issue The example provides a React app file structure which has at most three levels of nesting within each global folder, useful so that you don’t get lost, but illustrates the simplicity side-effect of applying the relationship-first structure. If we keep our components simple, our containers folder, the one which is nested the deepest, will never have to go more than three levels deep.
  4. Index files are present for clean importing This is honestly just a nice-to-have. If you use aliases for your imports, this may not be necessary.

Coming up with the perfect file structure for your React project is not impossible, it just takes a bit of experimentation. The React docs also have a great bit of advice on file structure if the above seems too complex for you:

If you feel completely stuck, start by keeping all files in a single folder. Eventually it will grow large enough that you will want to separate some files from the rest. By that time you’ll have enough knowledge to tell which files you edit together most often. In general, it is a good idea to keep files that often change together close to each other.¹

If anyone ever suggests that there is only one way to approach the implementation of a file structure in a React app then they are dead wrong. File structures change from project to project and from team to team. You may find that the discussion above on developing a file structure may work, but might need a dash of experimental reasoning when it comes to your own codebase. Simply remember that an effective file structure is often reliant on being able to do the following two things in the most efficient, most elegant way possible:

  • Folder traversal and being able to bypass the side effects of deep nesting
  • Reflecting impact across code (how a component or module may be used in a page or elsewhere), whether imposed by commonality or by relationship

[1]: React docs

JavaScript
React
Programming Tips
React Tips
Web Development
Recommended from ReadMedium