Introduction
In the
previous article, we have learned about using useReducer() hook and how it is used in React. Now, in this article, we will learn about the importance of useCallback() hook and why this hook is required.
useCallback() hook
In React, useCallback() hook is another important hook which is used for performance optimization. When we implement or call any component, all components re-render every time any call is made. For a small application, it will not have much effect. But when dealing with a large application, it will give performance issues. So, useCallback() provides a way to render components only when required.
Let’s look at the demo.
Create 4 components.
Title.js
- import React from 'react'
-
- function Title() {
- console.log("Title component rendered")
- return (
-
- <div>
- React Title
- </div>
- )
- }
-
- export default Title
Button.js
- import React from 'react'
-
- function Button({count,handleClick}) {
-
- console.log("Button Component rendered")
- return (
- <div>
- <p>Counter : {count}</p>
- <button onClick={handleClick}>Increment Counter</button>
- </div>
- )
- }
-
- export default Button
Textbox.js
- import React from 'react'
-
- function Textbox({name,handleClick}) {
- console.log("Textbox Rendered")
- return (
- <div>
- <input type="text" placeholder="Enter Name" value={name} onChange={handleClick}/>
- </div>
- )
- }
-
- export default Textbox
Parent.js
- import React, { useState } from 'react';
- import Title from './components/Title';
- import Button from './components/Button';
- import Textbox from './components/Textbox';
-
- function Parent() {
-
- const [count, setCount] = useState(0)
- const [name, setName] = useState("")
-
- const incrementCounter = () => {
- setCount(count + 1)
- }
-
- const updateName = (e) => {
- setName(e.target.value)
- }
-
- return (
- <div className="App">
- <Title />
-
- <Button count={count} handleClick={incrementCounter} />
-
- <label>Name is {name}</label>
- <Textbox text={name} handleClick={updateName} />
- </div>
- );
- }
-
- export default Parent;
The output will be displayed as below.
Initially, it will render as below.
On click of a button, we can check in the console that all components are rendered again even if there is the change in a single component.
Now, the same - even if a change in a textbox is made, all components are rendered again.
So, to avoid the rerendering of components, there is a need for useCallback().
Now, while the exporting component adds React.Memo() function, it will render only if there will be a change in props or state.
Title.js
- import React from 'react'
-
- function Title() {
- console.log("Title component rendered")
- return (
-
- <div>
- React Title
- </div>
- )
- }
-
- export default React.memo(Title)
Button.js
- import React from 'react'
-
- function Button({count,handleClick}) {
-
- console.log("Button Component rendered")
- return (
- <div>
- <p>Counter : {count}</p>
- <button onClick={handleClick}>Increment Counter</button>
- </div>
- )
- }
-
- export default React.memo(Button)
Textbox.js
- import React from 'react'
-
- function Textbox({name,handleClick}) {
- console.log("Textbox Rendered")
- return (
- <div>
- <input type="text" placeholder="Enter Name" value={name} onChange={handleClick}/>
- </div>
- )
- }
-
- export default React.memo(Textbox)
Now, check the output. Initially, it will render all 3 components.
After clicking on the button, the Title component will not be rendered.
So, to resolve the issue of the re-rendering components, if there is no change in the component useCallback() hook is used.
useCallback() hook will return a memorized version of the callback function that will change only when dependencies have changed. It is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
Now add callback function in Parent.js
- import React, { useState,useCallback } from 'react'
- import Title from './Title';
- import Button from './Button';
- import Textbox from './Textbox';
-
- function Parent() {
- const [count, setCount] = useState(0)
- const [name, setName] = useState("")
-
- const incrementCounter = useCallback(() => {
- setCount(count + 1)
- },[count])
-
- const updateName = useCallback((e) => {
- setName(e.target.value)
- },[name])
-
- return (
- <div>
- <Title />
-
- <Button count={count} handleClick={incrementCounter} />
- <label>Name is {name}</label>
- <Textbox text={name} handleClick={updateName} />
- </div>
- )
- }
-
- export default Parent
The output will be displayed as below.
Now, on click of a button, only the button component is rendered.
Now, on typing in textbox, the textbox component is rendered.
So, this way, we can optimize performance.
useCallback() hook provides an efficient way to write code and organize components by rendering a component only when it is required which also provide performance improvement and code optimization. It is used with React.memo() which makes sure that the no extra render should be performed unnecessarily. So, this way the complete flow works.
Summary
In this article, we have learned about useCallback() hook and how to use it. You can download the source code attached along with this article. In the next article, we will learn about useMemo() hook and its use in ReactJS.