First of all, you must read the document before understanding
Official address: Hook API Index – React https://zh-hans.reactjs.org/docs/hooks-reference.html#usecallback
Pass an inline callback function and an array of dependencies as parameters useCallback
, and it will return a memoized version of the callback function that will only be updated when a dependency changes. It is useful when you pass callbacks to shouldComponentUpdate
child components that are optimized and use reference equality to avoid unnecessary rendering (for example).
We can see the official sentence, let me explain its specific meaning with an example
First, create a Test.js component that receives a value props, don't forget that its subcomponents need React.memo package
import React from "react"
import { useDispatch } from "react-redux"
import { increment } from "../features/counterSlice"
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch()
const incrementCounter = () => dispatch(increment())
return (
<div>
<span>{value}</span>
<MyIncrementButton onIncrement={incrementCounter} />
</div>
)
}
export const MyIncrementButton = React.memo(({ onIncrement }) => {
console.log('render')
return <button onClick={onIncrement}>Increment counter</button>
})
Our counterSlice.js code is as follows
import { createSlice } from '@reduxjs/toolkit';
export const counterSlice = createSlice({
name: 'counter',
initialState: {
value: 0
},
reducers: {
increment: (state) => {
state.value += 1;
}
}
});
export const { increment } = counterSlice.actions;
export default counterSlice.reducer;
Remember not to forget to inject in store.reducer
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counterSlice';
export const store = configureStore({
reducer: {
counter: counterReducer,
},
});
Then we use this component in App.js
import React from 'react';
import { CounterComponent } from './components/Test';
import { useSelector } from 'react-redux'
function App() {
const count = useSelector(state => state.counter.value)
return (
<div className="App">
<CounterComponent value={count} />
</div>
);
}
export default App;
After starting the project, we click the increment counter button, and we can see that the console has been printing render
This is not what we want, because after we changed the counter, the child component MyIncrementButton did not have any other modifications, so it should not be re-rendered
So let's change the CounterComponent component
import React, { useCallback } from "react"
import { useDispatch } from "react-redux"
import { increment } from "../features/counter/counterSlice"
export const CounterComponent = ({ value }) => {
const dispatch = useDispatch()
const incrementCounter = useCallback(() => dispatch(increment()), [dispatch])
return (
<div>
<span>{value}</span>
<MyIncrementButton onIncrement={incrementCounter} />
</div>
)
}
export const MyIncrementButton = React.memo(({ onIncrement }) => {
console.log('render')
return <button onClick={onIncrement}>Increment counter</button>
})
Add useCallback to it
At this time, when we click the increment counter button again, we will find that the console does not continue to print render
This is because the second parameter of useCallback indicates that the dispatch has not changed, so the value returned by the hook will not change, and then the subcomponent will not be rendered. The use of useCallback greatly optimizes the loading speed of the page. You should often Use this application scenario
The same optimization also has useSelector, please refer to CSDN https://mp.csdn.net/mp_blog/creation/editor/120859456