Optimization, the React way
Tags: react, performance, javascript, webdev
Published: 2021-04-30 10:58:56

In this article, you'll learn about some of the best practices and how to optimize your React Web Application and create reusable components.

1.Debouncing and Throttling: These are both optimization concepts which limit rate off function calls(API calls, loggers) with a delay.

Debouncing:It takes a function and a delay and makes the function call only if the time interval between 2 calls is greater than delay. Use case: Search bar, scroll.
```javascript
const debounce=function(fn,d){
let timer;
return function(){
 let context=this,args=arguments;
 clearTimeout(timer);
 timer=setTimeout(()=>{
   fn.apply(context,args)
   },d);
  }
};
```
Throttling:It takes a function and a limit and makes the function call after the interval. Use case: Search bar, scroll.
```javascript
const throttle=function(fn,limit){
let flag=true;
return function(){
 let context=this,args=arguments;
 if(flag){
 fn.apply(context,args);
 flag=false;
 setTimeout(()=>{
   flag=true;
   },limit);
  }
 }
};
```
Instead of writing them on your own, one can leverage it from Lodash as well.

2.Component Composition: An alternative to prop drilling without using Redux or context API is Component composition. It relies heavily on the untamed power of children props.

```javascript
export default function App() {
  const content = "Inner most passed prop";
 return (
    <div className="App">
      <Dashboard>
         <ComponentNeedingProps content={content}  />
      </Dashboard>
    </div>
  );
}

function Dashboard({ children }) {
  return (
    <div>
      <h3>I am the dashboard but i do not need props</h3>;
     { children }
    </div>
  );
}

function ComponentNeedingProps({ content }) {
  return <h3>{content}</h3>
}
```

3.Custom Hooks: A reusable custom hook is used to avoid creating too many similar components that share the same logic. It also improves the code of your application by removing duplicate code, making your application easier to maintain. Let's create a custom hook named useToggle that returns a status state and a toggleStatus handler function:
```javascript
import { useState, useCallback, useMemo } from "react";

const useToggle = () => {
  const [status, setStatus] = useState(false);

  const toggleStatus = useCallback(() => {
    setStatus((prevStatus) => !prevStatus);
  }, []);

  const values = useMemo(
    () => ({
      status,
      toggleStatus
    }),
    [status, toggleStatus]
  );

  return values;
};

export default useToggle;
```
We can now reuse our new custom hook as many times as needed in any component that will take advantage of using this shared logic.

4.Optional Chaining and Nullish coalescing: Whenever you access a nested object property where you do not know if the sub object exists or not, we use && operator to check.
```javascript
const nestedObject = {
    profile:{
      name: "Prakhar",
      details: {
          age: 22
}}}
if (nestedObject && nestedObject.profile && nestedObject.profile.details) {
    console.log(nestedObject.profile.details.age); // 22
}
```
Now with optional chaining 
```javascript
console.log(nestedObject?.profile?.details?.age); //22
```
Nullish coalescing operator (??) is a logical operator that returns its right-hand side expression when its left-hand side expression is null or undefined, and otherwise returns its left-hand side expression. Combining this with optional chaining we get:
```javascript
console.log(nestedObject?.profile?.details?.address ?? "Address not specified"); //Address not specified
```
5.Memoization: It is basically a form of optimization used mainly to speed up code by storing the results of expensive function calls and returning the stored result whenever the same expensive function is called again.
```javascript
export function Sample({ name, age }) {
  return (
    <div>
      <div>Name: {name}</div>
      <div>Age: {age}</div>
    </div>
  );
}
// memoize the component
export const MemoizedSample = React.memo(Sample);

//Now when we call it
// On first render, React calls MemoizedSample function.
<MemoizedSample
  name="Alex"
  age=22
/>

// On next render, React does not call MemoizedSample function,
// preventing rendering as the props are same
<MemoizedSample
  name="Alex"
  age=22
/>

```
6.Anonymous Functions: Avoid anonymous functions as they aren’t assigned an identifier (const/let/var), they aren’t persistent whenever a component inevitably gets rendered again. This causes JavaScript to allocate new memory each time this component is re-rendered, instead of allocating a single piece of memory only once, like when named functions are being used.

There are many other ways of improving the performance of your React application and many blogs on it as well. If you have any questions, feel free to ask.

Happy Coding!