React.js Best Practices & Patterns - Part 2
Separation of concerns for high-quality applications
Introduction:
This article is part of a series of three articles that review some of the best techniques and patterns for working with React.js. In this article, we will delve into topics such as custom hooks and services, and determine the most suitable implementation approach for each. These techniques are designed to enhance the scalability and maintainability of your code. Throughout the article, you will find code snippets and valuable tips to effectively incorporate these best practices into your projects.
đFeel free to explore the initial segment of this article â go ahead and give it a read!
React.js Best Practices & Patterns - Part 1
Best practices for high-quality applications
Separation of Concerns
In software development, concern separation is critical. Itâs all about ensuring that each component of your program serves a single purpose. Separating the logic from the view in React.js can help make your code more maintainable, reusable, and scalable. So letâs look at some examples and approaches to help us create this separation and improve our React projects.
1. Custom Hooks
Custom hooks allow you to extract stateful logic from your components and apply it to multiple components. Custom hooks are just JavaScript functions with a unique name convention: they must begin with âuseâ (for example, useForm). These hooks can be used in conjunction with other built-in or custom hooks, and they can export an object or an array containing all of the attributes and methods that you want to use in your components.
letâs see some examples to understand how custom hooks might improve your React.js code:
đ Example 2: Custom Hook for Form Input Handling
Consider a form with numerous input fields. Handling the status and input for each field can become tedious and time-consuming. But donât worry, we can simplify things with a custom hook named useForm. This hook allows you to extract the state and logic for all of those fields while keeping things tidy.
First, we build a values object using useState to hold all of our form input values. Then, whenever an input changes, we call the handleChange method, which updates the values object. Finally, we include a resetForm method that resets everything to zero.
We can utilize these attributes and methods in all of our components by putting values, handleChange, and resetForm in an array. This makes our form component much easier to maintain and reuse.
Now, we can use the useForm custom hook in our form component:
As you see, the useForm custom hook helps us handle form inputs with ease.
Letâs take a look at another example.
đ Example 2: Custom Hook for Fetching Data
You can also use custom hooks to retrieve data from an API. Itâs actually quite common(you can see ReactQuery). All we need to do is create a custom hook called useFetch that handles the state and side effects of fetching data. Sahla-Mahla(Easy-peasy)!
Now, you can use the useFetch custom hook in any component that requires data from an API:
Now, we can simply handle the state and logic for fetching data from the view in our UserList component thanks to the useFetch custom hook. This greatly simplifies the maintenance and reuse of our code. We can maintain all of the state and side effects associated with fetching data in one place with useFetch, then use the generated data in different components. Because of this separation of responsibilities, we can quickly update our data-fetching mechanism without affecting the components that rely on it.
Overall, it improves the maintainability and scalability of our code.
2. Services
Using services to make your React projects more modular is a smart way to go. Services are methods or classes that conduct business logic such as calling APIs, manipulating data, and other useful tasks. These services can be imported and used in your components or custom hooks. Itâs a simple technique to keep things tidy by separating logic from view.
Letâs take a look at an example to gain a better understanding.
đ Example 1: API Service
Assume we need to use a RESTful API to do certain CRUD operations on user data. To make things easier, we can develop a service that handles everything. Itâs a convenient way to interface with the API and complete our jobs quickly.
Now, we can use the API service in our components or custom hooks: We can keep all of the API interaction logic separate from the view in our UserList component thanks to the API service. In this manner, we can easily maintain and reuse our code. Itâs a terrific approach to keep everything organized and manageable.
One more example wouldnât hurt.
đExample 2: Utility Service
Assume we need to accomplish something useful, such as formatting dates, calculating sums, or generating unique IDs. We can design a useful utility service that will take care of everything. Itâs like having our own personal assistant that we can call on whenever we need to get some meaningful work done. Cool! We can easily use our utility service in our components or custom hooks to make our code more efficient and reusable. Itâs a great way to keep things organized and make sure everything runs smoothly. By using the utility service, weâve kept the utility logic separate from the view, making our TransactionList component easier to manage and reuse.
3. When to use a Custom Hook and when to use a Service Function
It is critical to analyze the individual use case and needs of your application when determining whether to utilize a custom hook or a service function. Custom hooks are more suited for managing state or context or for reusing functionality across several components. Service functions, on the other hand, are better suited for reusable logic that does not depend on state or context.
In practice, you may find that some functionality fits better as a custom hook, while other functionality works better as a service function. For example, here are some more examples of when you might choose to use each approach:
Custom Hooks:
- Managing complex state: If you find yourself needing to manage complex state across multiple components, itâs recommended to utilize Custom hooks. For instance, if youâre tasked with overseeing a userâs preferences and correlating them with your product, a custom hook such as âuseUserSettingsâ could prove invaluable. This hook would assist in keeping track of the userâs preferences state and offer functionality to validate their compatibility with your product.
- Context-dependent functionality: A custom hook can assist in accessing context from different components and offering reusable functionality. For instance, if you need to manage user authentication across multiple components, a custom hook like âuseLoggedUserâ could enable you to access the user authentication state and provide the capability to manage or update it from other components.
Service Functions:
- Task-specific functionality: If you have a task that is unrelated to context or state management, employing a service function can be an effective strategy. For instance, when thereâs a need to validate data such as email or password or perform certain formatting operations, service functions can offer these functionalities without necessitating context or state involvement.
- Standalone functionality: If you intend to offer functionality that can be utilized across various applications or platforms, employing a service function is a valuable approach for encapsulating and ensuring the reusability of that logic. For instance, whether you require a function for image processing, file storage, email transmission, or payment processing, service functions can deliver these capabilities in a manner conducive to their application across a diverse range of applications or platforms.
Conclusion:
In conclusion, separation of concerns is a principle used in programming to separate an application into units, with minimal overlapping between the functions of the individual units. To achieve this in React.js applications you could use custom hooks or service functions.
Alternatively, neglecting to apply utilize separation of concerns principle could result in code that becomes less maintainable and organized, often leading to whatâs commonly referred to as âcode smells.â đ¤˘
Thank you for reading! Like for this article as much as you can.
đŠ For similar content, feel free to follow me and subscribe to my newsletter.
đ You can say hello here.
Share article
- web development
- Equality
- frontend
- Social