This content originally appeared on Level Up Coding - Medium and was authored by Imran Farooq
I have been working as a React developer since 2018 and there is no single great practice to structure and design a React app. At the micro level, there are some fine practices but if you are working in a team then the team has its own architecture.
For sure there is no universal best practice that you can apply to every business and application but for the productive codebase, we can follow some general rules. To keep an app productive and flexible we have to follow the software’s architecture and design. We have to work on it effectively and change it without rewriting its base code.
In this article, I am going to put some light on the principles and rules that have worked for me and my colleagues. I am going to define fantastic practices about components, data fetching, state management, styling, testing, and application architecture.
There are multiple ways to develop software. So take this article as my opinion.
Components
Sweet Functional Components
Functional Components have very simple syntax. You don’t have to worry about boilerplate-like lifecycle methods and constructors. with fewer characters and without losing readability you can express the same logic.
Write Consistent Components
You should stick to one style for the Components. Make sure to put your helper functions in the same place. Keep in your mind there will be no one best approach. Either you will export at the end of the component file or while defining the Component choose one and stick to it.
Naming the Components
You should always give names to the Components. It will help you to track the error with React Dev Tools.
Organizing Helper Functions
Don’t define your helper functions after your Component. The best place to define helper functions is before the Component so the file can easily be readable from top to bottom. You should keep a little amount of the helper function in the Component. You should pass the values from the state as arguments.
Never Hardcode Markup
You should refrain from hardcoding the markup for filters, navigation, or lists and go for configuration objects then loop through these items.
Length of the Component
A Component in React is just a function that can take props as arguments and return markup. Divide the Component into smaller Components if you have complex functionality. You should take help from props and callback functions for communication and data sharing between the Components. Lines of code do not matter, it is the logic that does matter.
Use Comments in JSX
Whenever you are implementing something important write comments in JSX. it is very important to give clarity in the form of comments if there is some logic in the markup.
Destructing of Props
As I described above React Components are functions and they are used to receive props and return markup so it makes sense to not use props everywhere.
Quantity of Props
Many readers of this article have an important question in their minds which is how many props a Component should have? The simple answer to this question is the more props a Component receives the Component has more reasons to re-render itself. You should give fewer amount props to a Component.
Prefer Objects over Primitives
Instead of using primitive values use objects in order to limit the number of props. A quick tip is to use TypeScript.
No More Nested Ternary Operators
After the first level, it becomes hard to read Ternary operators so avoid using nested Ternary operators as much as you can.
Use Separate Component for Lists
Looping over the list items is a common event and we developers use the Map function for this purpose but if a Component has too much mark up the map function creates some readability issues. If the markup is long or complicated use a single mapping per Component.
When Destructuring Assign Default Props
We can specify default values by attaching a default props property to the Component. While destructuring the props try to assign default at that time it will increase the readability of the code from top to bottom.
No More Nested Render Functions
Whenever you need to use markup from a Component don’t define it in a function living in the same Component. Create another Component, move it there name it properly, and depend on props instead of closure.
State Management
Use Reducers
As a developer, we sometimes need a more strong way to manage state changes. Before using any external library start using useReducer.To tackle complex state management it is an awesome method and for sure no 3rd party dependency is required. useReducer can be very powerful if we use it with the combination of React’s Context and TypeScript. Sadly it is not used by many of us. We are keen to use 3rd party libraries.
Favor Hooks to HOCs and Render Prop
As developers sometimes we want to enhance the Component or give it access to an external state. Usually, there are 3 ways to do it that are as follow
- Higher-order Component
- Render props
- Hooks
To achieve such composition hooks can be proven very efficient. As we all know Component is just a function that can use other functions. Hooks can allow us to use many sources of external functionality without clashing with each other and we can use as many hooks as we need.
We get values as props with HOCs. It makes it very difficult for us to determine whether values are coming from the parent or wrapping Component.
Render props can lead to the worst readability. If we nest multiple Components with render props the markup will look very bad.
Utilize Data Fetching Libraries
Many times while working on a project the data we want to manage in the state is received from API in multiple places we need to keep that data in memory, update it and access it. React Query which is a modern data fetching library has many mechanisms to manage the external data. We can cache data, invalidate data and fetch new data. If we compare React Query with GraphQL with an Apollo client then GraphQL wins because it is easy to use GraphQL.
State Management Libraries
Most of the time we do not need any state management library but if we are developing a large app we need to use a state library to manage complex state. There are many state management libraries. I would like to mention the two which I used the most first is Redux and the second is Recoil.
Mental Models Component
Smart & Dumb
The primary line of thinking is to split components into two groups — smart and dumb components. They are also known as containers and presentational.
The main idea behind the dumb Components is that they don’t have any logic and state. On the other hand, smart Components are those Components that have business logic, state and can be used to fetch data.
Stateless & Stateful
We can think of Components as stateless and stateful. As I mentioned above, some Components manage a lot of complexity which is why we should spread it throughout the application.
We should keep data close to these Components. When we are using a GraphQL client we fetch data in the Component that displays it. We should consider it as the most rational place to manage the state.
For example, the data of a form is handled by the <Form /> Component. The <Input /> will be getting values and calling functions when the changes occur. When the <Button /> is pressed by the user the form will be notified and the form will handle what will happen.
Now the question is who will take care of form validation? Will input take care of that? It will mean that this Component will become aware of the business rationale of our app.
How will the form be notified that there is an error? How will the state be refreshed on the basis of that error? If the user is trying to submit the form what will happen if there’s an error?
Whenever we are facing these questions we should become aware of the responsibilities that are getting mixed up. In that case, we should not give any state to input and the form will give an error message.
Application structure
Combine with Route/Module
The application will become hard to navigate if we group it by containers and Components. You need a good level of judgment to judge what Component belongs where.
All Components are not equal Some of the Components are used globally and some are developed for a particular part of the application. For small projects, this structure works well.
Combine with route/module from start. This is the composition that aids change and growth. The idea is not to have our application offshoot the architecture rapidly. If our application is based on Components and containers that will take place too quickly.
On the other side, the route/module-based architecture is facile to extend. I just want to clear one thing that Component and container architecture is not wrong but it is too common.
Make a common module
We usually use Components like cards, inputs, and buttons all over the application. It is good practice to extract those even if we are not using module-based architecture.
We should always see what common Components we have even if we are not using Storybook. It will aid to avoid replication and we don’t want everyone in our team to create their own version of the button. Regrettably, this occurs way too frequently because of poorly structured projects.
Make use of Absolute Path
We should make things easier to change as elementary for our project structure. Absolute paths mean that we will have to change less if we want to move a Component.
Enfold External Components
We should not import too many 3rd party Components directly instead we should develop an adapter around them. We can implement this for UI libraries like BootStrap or Material UI. The easiest thing that we can do is to re-export them from a common module.
Shift Components in Folders
For each module, I love to create a Components folder in my React applications. On any occasion I need to create a Component I create it there first. I create its own folder if it needs extra files like tests or styles.
Performance
Don’t Try To Optimize Prematurely
Before making any kind of optimization, we should make sure there is a reason for that. Don’t follow any best practice blindly check whether it is useful for our project. Before taking performance into consideration make sure to build maintainable and readable Components.
If you find any performance issue in your app tries to find the reason behind it. When you come to know the reason behind the performance issue, solve it in the order of its impact.
Observe The Bundle Size
The most important factor that can affect our application is the amount of JavaScript that has to be sent to the browser. Do not send JavaScript in a single bundle. We should divide our application at the route level. Try to send the least amount of JavaScript to the browser.
Testing
Don’t Depend on Snapshot Tests
I have been working with React since 2018. You will be surprised to know that the snapshot test helped me once to find a problem in my Components. Besides it, the snapshot test usually failed to find any error in my Components.
Test Correct Rendering
The core thing that our tests should validate is if the Component works as expected. We should make sure that the Component renders rightly with its default props.
Code Integration Tests
If we want to validate the entire page or large a Component then we should code integration tests. They will help us to know that the application is working as expected.
Styling
Utilize CSS-in-JS
I love to use 3rd party libraries like Styled Components or Emotion as they allow us to write CSS in JS and we don’t need to think about CSS convention. I know some people will not agree with me so I want to clear there is nothing wrong with using SCSS or CSS modules.
Maintain Styled Components Together
When it comes to CSS in JS components it is normal to have more than one in the same file. Preferably we would like to maintain them in the same file as the regular Component that uses them. Although, if they become too large, as styles can get, take out them in their own file living next to the component that uses them.
Buy Me A Cup Of Coffee
if you’re enjoying my article. I would appreciate a coffee to help me keep writing.
Imran Farooq is love to write on React js
React Best Practices for Software Design and Architecture was originally published in Level Up Coding on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Level Up Coding - Medium and was authored by Imran Farooq
Imran Farooq | Sciencx (2022-10-03T18:01:10+00:00) React Best Practices for Software Design and Architecture. Retrieved from https://www.scien.cx/2022/10/03/react-best-practices-for-software-design-and-architecture/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.