It’s one thing to write code. It’s another to write scalable code. All code infrastructures for softwares (especially for enterprises or small businesses) need regular updates. Your code’s ability to adapt to new requirements with less stress and fewer codebase changes makes it scalable.
Imagine joining a team and having to write many lines of code for a particular feature (i.e., writing new sets of queries or declaring new functions). Or imagine entering a company’s codebase for the first time and seeing it doesn’t follow some coding standards. I am sure you would feel very uncomfortable working there. From a business’s perspective, imagine having a particular code infrastructure that has code breaks. It can be very bad for business. In such instances, we say that the code was not scalable.
Scalability is defined as the essential and desirable part of a system that indicates its ability to adapt to changes in a graceful way.
In this article, we will be looking at scalability issues while moving our spotlight to React. React is a popular framework by Facebook. Its USP is that it allows developers to work with virtual DOM, which is why developers love it. Also, React makes the creation of UIs so easy. You just need to know HTML and Javascript.
However, as brilliant as this Javascript framework is, it is not above having scalability issues, especially if it is used by someone who does not fully understand writing scalable code.
What Are Common Scalability Issues?
When we write code, there are many things we consider, and scalability tops that list. So what are the things to look out for when it comes to scalability?
- Less stress in adding or maintaining code
- Reusability of functions
- Ability to handle complex and heavy tasks
However, over the years, a couple of scalability issues have been identified in React. Let’s take a look at these issues.
Confusing Classes
In the past, we had to depend on React life cycle methods, such as componentDidUpdate, and state-handling methods, such as this.setState, to deal with state changes. React classes, especially in the context of JavaScript objects, are hard to read and understand for both humans and machines.
Wrapper Hell
Before Hooks, if we wanted to encapsulate state management logic, we had to use higher-order components and render props. Using many contexts will result in a large tree with many sub-trees, also called wrapper hell. For example, when we want to use multiple contexts, the wrapper hell looks as follows:
<AuthContext.Consumer>
{user => (
<LangContext.Consumer>
{lang=> (
<CareerContext.Consumer>
{lang=> (
… more nested contex
)}
</CareerContext.Consumer>
)}
</LangContext.Consumer>
)}
</AuthContext.Consumer>>
This is not very easy to read or write. It is also prone to develop errors if we need to change something later on. Furthermore, the wrapper hell makes debugging hard because we need to look at a large component tree with many components acting only as wrappers.
Hooks in Scalable Code
In this article, we will look at some hooks regarding writing scalable codes to handle heavy tasks. We will then look at tools like Frontegg that solve scalability issues in React.
These are some of the commonly used hooks in no particular order:
- useState
- useEffect
- useContext
- useMemo
- useReduce
This article will not discuss these hooks extensively. It will shed light on them to give us a basic understanding of how we can use hooks to solve scalability issues in React.
useState
This is one of the most commonly used hooks, maybe the most common, in React applications. It is made up of a variable and a setter function.
The useState hook is used to deal with the state in React. We can use it as follows:
import { useState } from ‘react’
const [ state, setState ] = useState(initialState)
This hook replaces this.state and this.setState() in class-based components.
useContext
If you have ever used React context, this is the hook you need. A context in React is a way to pass data between different components without the need to cascade props manually. It is useful, for example, when we want to create themes or locations that are to be used for the entire component tree. Otherwise, it can be cumbersome to have to propagate them for each added component.
In class components, the context is passed through a provider. This provider encompasses the tree of components that must have that context. This hook accepts a context object and returns the current context value. The useContext hook is used to deal with context in React. We can use it as follows:
import { useContext } from ‘react’
const value = useContext(MyContext)
The useContext hook replaces context consumers, which has been discussed in the wrapper hell scalability issue. Furthermore, it provides state updates on multiple layers of children components. So useContext is an easy alternative if we just need to pass the data to the children.
useReducer
The useReducer hook used in the Redux library works the same way as the useState hook. We can use it as follows:
import { useReducer } from ‘react’
const [ state, dispatch ] = useReducer(reducer, initialArg, init)
The useReducer hook is used to handle complex state logic. As mentioned above, it is similar to the useState hook. The difference between them is that useReducer holds multiple state variables while useState can only hold a single state value.
useMemo
import React, {useState, useContext, useMemo, useReducer} from ‘react’;
When our state is updated, it triggers the calculation of each previous value, which is unnecessary. To avoid this, we need to use concept memorization, where the most recent calculated value is cached for later use. The useMemo comes in very handy here. useMemo helps optimize performance as it executes on every render but only if one of the dependencies changes.
useEffect
The useEffect hook replaces the use of the componentDidMount, componentDidUpdate, and componentWillUnmount methods in class-based components.
The useEffect hook comes very handy when dealing with high-effect codes, such as timers, subscriptions, requests, and so on. Furthermore, the useEffect hook allows for returning a cleanup function from it, which is like adding a function to componentWillUnmount.
We can use it as follows:
import React, { useEffect } from ‘react’;
useEffect(() => {…});
Decouple Component Logic with Custom Hooks
As your project grows, you might notice that some of your component’s logic seems to get used repeatedly. To share your component’s logic, you need to write a custom hook. Hooks allow React to handle various optimizations on our code since it is easier to analyze functions and function calls than classes and their complex behavior.
While hooks are helpful, there are easier ways. There are countless tools in this market that can assist with scalability issues and how to manage them. Here are a couple:
1. Frontegg
Frontegg is a platform that goes beyond user management. It is intended to take away the hassles of user management and reduces scalability issues to the minimum. It’s also free-to-use from small-scale projects up to 10 MAT so you can get familiarized with everything before diving into the platform head-first.
Frontegg contains many features like authentication, SSO and social logins, API tokens, user management, webhooks, etc. This platform has a lot to offer in terms of helping developers reduce their workload and reduce the lines of code they write, which in turn helps scalability.
2. Okta
Okta specializes in identity security through their platform, so if you expect to have a lot of confidential, personal, and identifying information on your platform, this may be a desirable solution. They also offer authentication and user management services for multiple languages. Specifically, the Auth0 combination can help your React application with multiple use cases. The developer version is free-to-use.
Conclusion
I hope you this article has taught you a lot. You have seen how to reduce scalability issues in your applications through hooks and tools. Just remember, simplicity is the ultimate sophistication. It’s not about having bulky lines of code but having lesser lines of code with more functions.