react 之 useCallback

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  shouldComponentUpdatechild 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

Guess you like

Origin blog.csdn.net/weixin_42335036/article/details/120862488