Check out my React hooks introduction first, if you’re new to them.
One React hook I sometimes use is useCallback
.
import React, { useCallback } from 'react'
This hook is useful when you have a component with a child frequently re-rendering, and you pass a callback to it:
import React, { useState, useCallback } from 'react'
const Counter = () => {
const [count, setCount] = useState(0)
const [otherCounter, setOtherCounter] = useState(0)
const increment = () => {
setCount(count + 1)
}
const decrement = () => {
setCount(count - 1)
}
const incrementOtherCounter = () => {
setOtherCounter(otherCounter + 1)
}
return (
<>
Count: {count}
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={incrementOtherCounter}>incrementOtherCounter</button>
</>
)
}
ReactDOM.render(<Counter />, document.getElementById('app'))
The problem here is that any time the counter is updated, all the 3 functions are re-created again.
You can visualize this by instantiating a Set data structure, and adding each function to it. Why Set? because it only stores unique elements, which in our case means different (uniquely instantiated) functions.
import React, { useState, useCallback } from 'react'
const functionsCounter = new Set()
const Counter = () => {
const [count, setCount] = useState(0)
const [otherCounter, setOtherCounter] = useState(0)
const increment = () => {
setCount(count + 1)
}
const decrement = () => {
setCount(count - 1)
}
const incrementOtherCounter = () => {
setOtherCounter(otherCounter + 1)
}
functionsCounter.add(increment)
functionsCounter.add(decrement)
functionsCounter.add(incrementOtherCounter)
alert(functionsCounter)
return (
<>
Count: {count}
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
<button onClick={incrementOtherCounter}>incrementOtherCounter</button>
</>
)
}
ReactDOM.render(<Counter />, document.getElementById('app'))
If you try out this code you’ll see the alert incrementing by 3 at a time.
What should happen instead it’s that if you increment one counter, all functions related to that counter should be re-instantiated.
If another state value is unchanged, it should not be touched.
Now, in most cases this is not a huge problem unless you are passing lots of different functions, all changing unrelated bits of data, that are proven to be a big cost for your app performance.
If that’s a problem, you can use useCallback
.
This is how we do it. Instead of:
const increment = (() => {
setCount(count + 1)
})
const decrement = (() => {
setCount(count - 1)
})
const incrementOtherCounter = (() => {
setOtherCounter(otherCounter + 1)
})
You wrap all those calls in:
const increment = useCallback(() => {
setCount(count + 1)
}, [count])
const decrement = useCallback(() => {
setCount(count - 1)
}, [count])
const incrementOtherCounter = useCallback(() => {
setOtherCounter(otherCounter + 1)
}, [otherCounter])
Make sure you add that array as a second parameter to useCallback()
with the state needed.
Now if you try to click one of the counters, only the functions related to the state that changes are going to be re-instantiated.
You can try this example on Codepen:
See the Pen React useCallback hook by Flavio Copes (@flaviocopes) on CodePen.
Download my free React Handbook
More react tutorials:
- A React simple app example: fetch GitHub users information via API
- Build a simple counter with React
- VS Code setup for React development
- How to pass props to a child component via React Router
- Create an app with Electron and React
- Tutorial: create a Spreadsheet using React
- The roadmap to learn React
- Learn how to use Redux
- Getting started with JSX
- Styled Components
- Introduction to Redux Saga
- Introduction to React Router
- Introduction to React
- React Components
- The Virtual DOM
- React Events
- The React State
- React Props
- The React Fragment
- The React Context API
- React PropTypes
- React concepts: declarative
- React: How to show a different component on click
- How to loop inside React JSX
- Props vs State in React
- Should you use jQuery or React?
- How much JavaScript you need to know to use React?
- Introduction to Gatsby
- How to reference a DOM element in React
- Unidirectional Data Flow in React
- React Higher Order Components
- React Lifecycle Events
- React Concept: Immutability
- React Concept: Purity
- Introduction to React Hooks
- Introduction to create-react-app
- React Concept: Composition
- React: Presentational vs Container Components
- Code Splitting in React
- Server Side Rendering with React
- How to install React
- CSS in React
- Using SASS in React
- Handling Forms in React
- React StrictMode
- React Portals
- React Render Props
- Testing React components
- How to pass a parameter to event handlers in React
- How to handle errors in React
- How to return multiple elements in JSX
- Conditional rendering in React
- React, how to transfer props to child components
- How to get the value of an input element in React
- How to use the useState React hook
- How to use the useCallback React hook
- How to use the useEffect React hook
- How to use the useMemo React hook
- How to use the useRef React hook
- How to use the useContext React hook
- How to use the useReducer React hook
- How to connect your React app to a backend on the same origin
- The Reach Router Tutorial
- How to use the React Developer Tools
- How to learn React
- How to debug a React application
- How to render HTML in React
- How to fix the `dangerouslySetInnerHTML` did not match error in React
- How I fixed an issue with a React login form state and Browser autofill
- How to configure HTTPS in a React app on localhost
- How to fix the "cannot update a component while rendering a different component" error in React
- Can I use React hooks inside a conditional?
- Using useState with an object: how to update
- How to move around blocks of code with React and Tailwind