Always Try to use Memoized Components in React
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:
- Might cause re-render when re-rendering is not needed
- 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