Always Try to use Memoized Components in React

Posted On 23 September 2020 ( 12.9 Minute Read )

By Addis Software

Because of the fact that whenever the states and props of react components or their parent components change the component and its child component will re-render, it will create a huge performance problem or might lead to infinite loop if not watched carefully and implemented with such appropriate caution.

Memoizing in React is a performance feature of the framework that aims to speed up the render process of components. The technique is used in a wide spectrum of disciplines, from game engines to web applications.

This article explores memoization techniques within React.


Memoizing is a well known concept in computer programming, aiming to speed up programs by caching results of expensive function calls and re-using those cached results to avoid repeating those expensive operations. While Memoizing often-times saves processing cycles, there is a limit to how much it can be used — this is of course dictated by a system’s memory limits.            

                
When it comes to React, we are caching the result of a component’s render() method — or simply the returned JSX of a functional component.


It is wise to consider how much of your application will be cached via memoizing Since mobile devices will inevitably have less memory to utilize than laptop or desktop counterparts.

here are two lists of ways that you can introduce memoization in react

1. Memoization with useMemo() and useCallback() hooks

Memorize hooks need to remember data or functions that:

  1. Might cause re-render when re-rendering is not needed
  2. Preserve or cache data or function so new copies are not created.
  • useMemo() returns a memoized value, 
useMemo(()=>{},[deps])
  • whereas useCallback returns a memoized callback
useCallback(()=>{},[deps])


Both React.useMemo and React.useCallback receive a function as its first argument and a dependencies array as the second one. The hook will return a new value only when one of the dependencies value changes.


The main difference is that React.useMemo will call a function and return its result while React.useCallback will return a function without calling it. The Memoized hooks caches the computationally expensive functions data and return them a given one of the dependency array is changed. 

2. Memoization with react Reselects


Well most of the time we often use reselectors in react state management tool with selectos. But before going to reselectors we have to understand what selectos are.


At their most simple, Selectors are simply functions that are used to select a subset data from a larger data collection. Basic selectors (i.e simple functions that return a subset of data) are beneficial because they encapsulate knowledge of where to find that particular subset of data, they are also reusable and flexible


Selectors:


1) Have knowledge of the whereabouts or path to find a particular subset of data and
2) Return with the requested subset of data


Why Use Reselect to Create Selectors?


The short answer is: for performance as Reselect provides a wrapper for creating selectors that are memoized.


The definitions of selectors that you’ve seen so far have only been responsible for retrieving data as it appears in the redux store. This would only likely be enough in small apps where the data that app needs can be found directly in the store. However, in larger and more complex apps, it’s advisable to keep the store with minimal amount of information as it cuts down on repetition and generally helps to avoid highly nested data that results in more complex reducer logic. This is especially relevant for apps that are structured with a normalized store. The biggest benefit of Reselect is that selectors created with the library are memoized and therefore will only re-run if their arguments change.


here is an example of selectors obtaining a specific data from redux state:                        
here a selector gets the belt data from shop store,


//selector.js
// Note: selectors are usually created in a relevant reducer file or a separate selectors file
const getBelts = (state) => state.shop.items.belts;
class DisplayBelts extends React.Component {
render() {
return this.props.belts.map(belt => );
}
}
// and specify the result of selectors data to props
const mapStateToProps = state => {
return {
belts: getBelts(state)
}
}


By doing this we encapsulate knowledge of where to find that particular subset of data, they are also reusable and flexible. But if we ask the selector to give us a data that is not different from the previous one the selector would have to go again and get the data for which it doesnt have to do, because it can easily cache the data in a memory and read  that cached data from memory the next time it is asked the get that data. This way it would a huge amount of computation, time and keeps the react  component from rerendering. This is a place to use Reselect


Reselect offers up a function called createSelector() that’s used to create memoized selectors

import { createSelector } from 'reselect'
const shopItemsSelector = state => state.shop.items
const taxPercentSelector = state => state.shop.taxPercent
const subtotalSelector = createSelector(
shopItemsSelector,
items => items.reduce((acc, item) => acc + item.value, 0)
)
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
)
export const totalSelector = createSelector(
subtotalSelector,
taxSelector,
(subtotal, tax) => ({ total: subtotal + tax })
)
To retrieve state in a component
import {totalSelector} from '/selector'
import {createStructuredSelector} from 'reselect'
class Inventory extends React.Component {
render() {
return The shop's total inventory is: ${this.props.inventoryValue}
}
}
const mapStateToProps = createStructuredSelector({
inventoryValue: totalSelector()
})


Memoizing Considerations
  • To use these APIs effectively, consider the following points to ensure your                        
    apps remain bug free while leveraging the performance gains of Memoizing:
  • Side effects (anything that affects something outside the scope of the                      
    function being executed) should not be performed in a memoized function.                    
    Leave this to the commit phase of the component, after its render phase has                          
    completed execution
  • Memoizing is performed in the render phase of a component, and side                        
    effects should typically be used in componentDidMount,            
    componentDidUpdate, and componentDidCatch with class components, or            
    useEffect with functional components
  • Use the Profiler to record the performance of your app before and after                          
    Memoizing. If the performance gains are not considerable, it may be worth                      
    removing the added complexity Memoization brings in certain areas of your                    
    app where there is not a huge performance gain, freeing up more memory and                         
    decreasing boilerplate
  • Compartmentalise a component into child components to leverage                
    memoization if you need to, such as in forms whereby static components such                       
    as buttons, labels and icons may be combined with dynamic components that                      
    need re-rendering, such as with validation. Separate these and memoize                  
    where possible — this is especially useful with complex SVG icons that contain                        
    a lot of markup