React Worst Practices — The Conclusion
Hello World !!!
There is one amazing thing about human behaviour, and that is doing one tiny good thing regularly makes our mind and body to develop muscle memory.
Example of some muscle memory instances are like, typing without seeing the keyboard, taking turns in known roads while being lost in own thoughts, eating in dark and many more.
Just like muscle memory makes us to take decision without having to pay attention, if somehow we develop this muscle memory while writing code, then it can bring amazing benefits to our codebase. Because then we don’t have to care about small things. We can totally dedicate our time in solving complex logic.
Some benefits of having good practices on finger tips are:
1. Manageable and maintainable code
2. Application will be less prone to crash due null values.
3. Improved load time
4. Reduced debug time.
5. Consistency in team work
Few months back I had shared few bad practices on ReactJS. If you haven’t checked them please have a peek to it, because this article is the continuation of the same.
So here goes the awsomeness
1. Importing unwanted modules
If we don’t pay attention to what we are importing then we are un-necessarily increasing bundle size of our application.
Consider below code snippet.
Here I am importing
get method of lodash only , but this method is not a good way to import anything.
In this method even though I am only using
get method, but behind the scences all methods are getting imported. Which in turn will increase our package size.
We should always check the way we are importing libraries and functions in our code.
The Recommended way is to import only those things which we need and this can be acheived by using default imports:
Here is the size comparison with both import styles:
2. Being Lazy when working with HTTP Requests
Consider following snippet, It has one button, on click of it we are fetching data and showing it in UI.
Trust me, I have seen such code in industry level applications with thousands of weekly users.
What’s the problem in above code?
Problem 1: There is no loading indicator to indicate that something is happening.
Problem 2: There is no mechanism to handle error. If the promise is rejected, user won’t be able to know that something bad happens and he may keep trying and eventually leave the application with bad experience.
So keep this in mind, whenever you are making any HTTP request. Make sure if user is waiting for it in UI then show something, and never skip to handle errors.
Demo with Success and Failure
4. Not harnessing the power of hooks
In my previous example, I’ve made an HTTP request in a component. Now suppose we have 100 component which need same implementation.
Like, fetch the data, show the indicator while fetching, once fetching done hide the indicator and show the data, and if error comes, show relevant message and way to react to the error if applicable.
Now some of may think of writing same code again and again. But that’s not the good way.
We can easily solve this problem by hooks. One of the main goal of with the introduction of hooks was to separate the logic from component.
To solve such problem we can create our own custom hook. Whose job will be:
1. Make HTTP Request
2. manage loading state
3. manage success state
4. manage error
5. manage data state in case of success
Let’s see it in code:
And in Action:
4. Not following any directory structure
Nowadays, we write less code compared to using pre-built methods from libraries. Due to this organising things becomes integral part of any project.
Organising things is always better, it keeps things accessible and saves browsing time.
There are many good resources out these for a good directory strucutre. I am listing few of them, you may pick any of it based on your personal preference and need:
File Structure - React
React doesn't have opinions on how you put files into folders. That said there are a few common approaches popular in…
5. Not breaking a large component into smaller one
I’ve seen many developers writing code for whole screen instead of creating smaller components. The reason they give about this is, they don’t want to manage large number of files, instead they want a big file.
Perosnally I do not like this approach at all. React itself says it is a Component-Based library. If we are working in React we should think in React Way.
We should break down our screen into components.
Let’s us understand this with an example. Here I am attaching a ScreenShot of React official doc. And I am giving both good way and bad way of design the screen:
Go Ahead, try yourself before seeing the actual breakdown.
With this approach, indeed we will get the same UI which we wanted and also we can save few minutes of our life by not creating re-usable components.
The downside of this approach is that, if we have to use same button and text component, then we have to write duplicate CSS and JSX code. Which in turn takes much time and increases the code size.
The React way of doing this is as follows:
We have Text component to take care of styles controlled by props. Similarly UI for Button component is controlled by props.
6. Spaghetti code in reusable components
Generally in our react application we create some re-usable components which are used throughout the project. Some good example of re-usable components are Button, Text , Checkbox.
The mistake we do in re-usable component is that we import other re-usable component to make a re-suable component.
Consider this code snippet:
In the above code, I’ve a re-usable Button Component, But inside it I am using Text Component.
The Problem with this approach is that, If I’ve to use this Button component in any of my other projects, or If I want to share it with other developers, then I’ve to also share the Text Component.
Here the Button Component is dependent on Text Component.
We should avoid such cases. Above component can be re-factored as:
Caviat: With this practice, Code will be duplicated. So we have to make decision here. If your re-usable component is specific to one project then you don’t have to worry about dependencies.
7. Not doing prop type validation checks
Frequent crashes may impact the user retention for any website.
For React component we can address this by two ways. First one is using TypeScript. If we are using typescript then we can use
interfaces to define the proptypes. So that only expected data type get assigned to a variable.
Another way we can address this is by using popular package called
8. Not using Error Boundaries
Error Boundaries helps us to handle errors gracefully. Most of wrap our whole React App in one Error Boundary and forget about it.
The draw back of this is that, If in any part of your application crash happens, then whole application will be come useless.
To handle such cases break your application in parts like:
And for such components, Wrap them in there individual ErrorBoundaries. So that if there is a crash in SideBar, rest of the application can still be used.
9. Not doing code splitting
Code Splitting help us to reduce the bundle size on initial launch and also while user is navigating between pages.
The consequence of not using it is that everything will be loaded in browser as soon as user hit the URL. And chances are 80% of things loaded, aren’t being used.
Types of Code Splitting:
1. Route Level
2. Component Level
3. Loading 3rd party import lazly.
10. Not following proper component naming convention
While we are in learning phase, we tend to do this mistake.
We give file name to components whatever we want and don’t case about any convention.
I am providing two recommended pratice for component naming convention:
- Component Names should start with caps. No dashes and no underscope. Separate words by another Capital Letter.
- create a folder, the name of this folder will be in lower letters. And inside this folder we create index.js. And we write all our component logic inside this index file.
11. Writing business logic in component file
Generally in most the react applications we have to write some code in order to get specific shape of objects or calculate some values.
Generally people write everything in component file. Which is bad practice. Component file is UI representation for your code and that’s it. We should always avoid writing any business logic to it.
We should have a separate
utility file, which holds all the methods which are commonly used and also which does some calculations.
We can have as many as utlity files based on need with descriptive names.
12. Not using logs in application
This is totally optional suggestion. This is not must have, but good to have suggestion.
In every react application we should have some sort of
log tracking and event tracking integrated. Few examples — MixPanel, LogEntries, Google Analytics, LogRocket.
The benefit for this is this will help us to see the user behaviour, which part of application is being used widely by users so that we can work upon that particular area.
This will also helps to identify bugs. If any users suffers a problem, we can check logs for that particular user and can easily backtrack the problem.
This will also help you to know from what different sources, countries users are visiting your website.
13. following props drilling
Props drilling means passing large number of props through component, and receiving them in child components.
Drawbacks of passing large number of props:
1. Hard to manage the component later (After few months)
2. Some child component may even not using the prop, but on prop change they will also re-render.
3. Complex and large component file.
What we can do to avoid it:1. Use Provider Context functionality. With Hooks it is more easy to use them
2. With the introduction of hooks, instead of using
mapStateToProps with HOC we can use
Due to this we can extract required redux state in component separatley.
In short, we will get only we want.
14. executing same code on multiple re-renders
Consider following code snippet
In above code, we have simple logic to filter array for
Now let us see the behaviour in browser. Pay attention to the console logs.
The main problem is that, on every state change the calculation logic is performed again and again. For smaller application this might not cause an issue, but as application size grows and we introduce complex logic on larger data set, our application will definitely going to suffer.
The solution for such scenarios are to cache such result. And
React provide us a
hook to do that. We can easily
memoize the result using
And if we can to re-calculate the logic based on any state variable, then simple pass that variable in the dependency array. (In our case I’ve passed it as an empty array)
15. using legacy JS code to access DOM elements
React is a declarative UI library.
It tends to hide all low level dom operations. But there may be countless number of cases where we have to access the dom elements.
Sometimes we use traditional
document.getElementById() code to access element.
This acceptable when we are working in traditional JS. But not in react. although it will work all the times.
In React the recommended way of accessing DOM elements is to use
And if somehow use ref is not solving the purpose then you may use
querySelectorAll which is faster than
document.getElementById . The only caviat of using
querySelector method is that they return the
cached copy of DOM element, which means if DOM is modified then
querySelector will still return the old cached DOM element. So keep this in mind while using this method.