Clean Code Idea For React.js

Clean Code Idea For React.js

Background idea: The first question that comes to our mind before implementing something is why we need to implement it. The reason behind using clean code is that it makes the code understandable, organized, readable, and well-structured for us and our team members. By using clean code, the code can be easily changed, extended, and maintained. A programmer's journey starts with solving problems, and the journey of professional software engineers begins with solving problems in an efficient way so that after coming back to their own code even after a few days, they will understand it well side by side their team members can also understand their code and use it effectively. And this is where clean code helps.

Below, I have mentioned some strategies I use to keep the codebase of my React.JS project clean.

Strategies:

  • When I write code, I follow certain naming conventions. For example, I use the pascal case for naming classes, such as class SingleTask{}. I use snake case for naming variables, such as const smallest_number = 0. And I use camel case for naming functions, such as function clickHandler(){}. These conventions help me to understand whether something is a class, a variable, or something else just by looking at its name.

  • I use meaningful, explanatory, descriptive, unambiguous, and pronounceable names for variables, functions, and classes so that it becomes easier to understand their purpose.

  • When I use a regex string, I give it a meaningful variable name so that the meaning of the regex string becomes more clear.

  • I try to declare variables as close as possible to where they are used in the code. So it becomes easy to find out the declaration and usage.

  • Various design patterns such as the factory design pattern, adapter design pattern, etc. can be very helpful in writing well-structured and scalable code.

  • When a function becomes too large, I break it down into smaller functions based on its operations. This makes it easier to understand the operations of the function and reduces its complexity. As a result, the function becomes simpler.

  • I prefer to avoid passing too many arguments in a function. Because passing too many arguments means the function is dealing with too many things which is making it complex. So I prefer at most 3 arguments in a function.

  • In the code, I prefer to organize similar and dependent functions close to each other.

  • I prefer using the if-else block rather than ternary conditions. Because in nested ternary conditions, it becomes difficult to keep track of the flow. Sometimes I use switch cases when there are too many else if blocks.

  • To make the meaning of a condition easily understandable, I keep the condition in a variable with proper naming.

  • Sometimes edge cases are forgotten to manage. To tackle this kind of situation I encapsulate their processing in a single place. This approach helps manage the complexity of boundary conditions.

  • Shortcuts are used to write less amount of code but sometimes it makes the code difficult to understand. As a result, it violates readability. In those cases, I choose readability over shortcuts.

  • I try to follow consistency in my code. If a task is performed using a particular method or approach, I apply that same method or approach to all similar tasks.

  • I try to write reusable code to avoid unnecessary duplication of the code.

  • We, as team members, use a common code formatter to format our code. If we use different code formatters, the version controller (Git) detects unnecessary changes during code commits. In this case, we use a VS Code extension named "Prettier" as our code formatter.

  • A linter is a tool used to enforce coding rules. If the rules are not followed, the linter will throw an error. I use the "ESLint" extension in VS Code to define the coding rules.

  • I prefer not to use inline styles in my code. Instead, I opt to use external CSS files or CSS modules. This practice results in cleaner and more readable code.

  • I prefer to use functional components more than class components in React because it allows me to use hooks and write cleaner and simpler code. And it is also easy to use. Moreover, functional components have updated documentation and libraries in React, it is recommended to use functional components instead of class components. Therefore, the community around functional components is strong, and almost all class-based applications are being migrated to function-based applications.

  • In React, I utilize keys within the list component to uniquely identify and track changes, updates, or deletions of individual items in the list. Keys essentially serve as identifiers for the elements within the list. By including keys, I can prevent unnecessary warnings and avoid potential errors in the browser.

  • I use react fragment instead of "div" to wrap a component. Because if we add a "div", then extra unnecessary nodes will be added to the DOM. But the fragment does not add any extra nodes. So it makes the rendering a little bit faster.

  • For the conditional rendering of a component, I tend to use ternary operators than &&. Because 0 and empty string are also falsy. So in the case of &&, for not meeting the condition, it shows an unnecessary 0 or empty string.

  • Using typescript is very handy for react-based projects. It gives type syntax functionality to JavaScript. Because of using typescript while passing props, developers do not need to memorize the props and their types. It suggests auto-completion for props. It also prohibited the wrong type of value passing. Which saves developers time.

  • If there are at most three levels to pass the data down manually, then I pass the data as props, otherwise, I store the data in the Redux store.

  • I try to pass as few props as possible to maintain the simplicity of the component. I prefer to use a maximum of five props.

  • When the data has multiple states I use Enum.

  • To keep the components clean and reduce complexity, I prefer to keep all data and operations related to a particular feature in a separate helper file. I organize the feature-related data, functions, and operations within a customized hook. This way, the component only focuses on rendering the view, and all the other logic and control are handled by the hook.

  • I try to create components that focus on a single task to keep them simple. When writing components, I attempt to keep the number of lines of code as low as possible. I aim for a maximum of 100-150 lines of code within a component.

  • I try to give a generic name to the component than the specific ones so that I can reuse the component in different features if needed. For example, if there are multiple features that require an input box, I name the component "inputBox" instead of "nameInputBox" since "nameInputBox" implies that it is only used for name properties.

  • I utilize useMemo, a higher-order component that can enhance the performance of my application by avoiding unnecessary re-renders. I implement it for components that do not require re-rendering every time.

  • I create a folder named "components," "hooks," and "utilities" within the "src" folder. The "hooks" and "utilities" folders contain customized hooks and utility-related files, respectively. Inside the "common" folder, there are subfolders organized based on the type of common and reusable components. Those subfolders basically contain a group of component files belonging to the type of that subfolder, such as different types of buttons within the "buttons" folder. The "components" folder contains feature-specific components that are not reusable directly, like a component for the order table viewer.