web-dev-qa-db-fra.com

Que font useCallback / useMemo dans React?

Comme indiqué dans docs , useCallback Renvoie un rappel mémo.

Passez un rappel en ligne et un tableau d'entrées. useCallback renverra une version mémoisée du rappel qui ne change que si l'une des entrées a été modifiée. Cela est utile lorsque vous transmettez des rappels à des composants enfants optimisés qui s'appuient sur une égalité de référence pour éviter les rendus inutiles (par exemple, shouldComponentUpdate).

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

Mais comment cela fonctionne-t-il et quel est le meilleur moyen de l'utiliser dans React?

P.S. Je pense que la visualisation avec exemple de codepen aidera tout le monde à mieux la comprendre. expliqué dans la documentation .

39
RTW

Ceci est mieux utilisé lorsque vous souhaitez éviter des rediffusions inutiles pour de meilleures performances.

Comparez ces deux manières de passer des callbacks aux composants enfants issus de React Docs :

1. Fonction de flèche dans le rendu

class Foo extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onClick={() => this.handleClick()}>Click Me</Button>;
  }
}

2. Lier dans le constructeur (ES2015)

class Foo extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onClick={this.handleClick}>Click Me</Button>;
  }
}

En supposant que <Button> soit implémenté en tant que PureComponent, le premier moyen provoque la restitution de <Button> à chaque fois que <Foo> est restitué, car une nouvelle fonction est créée à chaque appel de render(). . De la deuxième manière, la méthode handleClick n'est créée qu'une seule fois dans le constructeur de <Foo> et est réutilisée dans les rendus.

Si nous traduisons les deux approches en composants fonctionnels à l'aide de points d'ancrage, ce sont les équivalents (en quelque sorte):

1. Fonction de flèche dans le rendu -> Rappel non mémorisé

function Foo() {
  const handleClick = () => {
    console.log('Click happened');
  }
  return <Button onClick={handleClick}>Click Me</Button>;
}

2. Bind in Constructor (ES2015) -> Rappels mémoisés

function Foo() {
  const memoizedHandleClick = useCallback(
    () => console.log('Click happened'), [],
  ); // Tells React to memoize regardless of arguments.
  return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}

La première façon crée des rappels à chaque appel du composant fonctionnel, mais dans la deuxième manière, React mémorise la fonction de rappel pour vous et le rappel n'est pas créé plusieurs fois.

Dans la plupart des cas, c'est bien de faire le premier chemin. Comme le React docs dit:

Est-il correct d'utiliser des fonctions de flèche dans les méthodes de rendu? De manière générale, oui, c'est correct et c'est souvent le moyen le plus simple de passer des paramètres à des fonctions de rappel .

Si vous avez des problèmes de performances, optimisez-les!

80
Yangshun Tay

J'ai créé un petit exemple pour aider les autres à mieux comprendre comment il se comporte. Vous pouvez lancer la démo ici ou lire le code ci-dessous:

import React, { useState, useCallback, useMemo } from 'react';
import { render } from 'react-dom';

const App = () => {
    const [state, changeState] = useState({});
    const memoizedValue = useMemo(() => Math.random(), []);
    const memoizedCallback = useCallback(() => console.log(memoizedValue), []);
    const unMemoizedCallback = () => console.log(memoizedValue);
    const {prevMemoizedCallback, prevUnMemoizedCallback} = state;
    return (
      <>
        <p>Memoized value: {memoizedValue}</p>
        <p>New update {Math.random()}</p>
        <p>is prevMemoizedCallback === to memoizedCallback: { String(prevMemoizedCallback === memoizedCallback)}</p>
        <p>is prevUnMemoizedCallback === to unMemoizedCallback: { String(prevUnMemoizedCallback === unMemoizedCallback) }</p>
        <p><button onClick={memoizedCallback}>memoizedCallback</button></p>
        <p><button onClick={unMemoizedCallback}>unMemoizedCallback</button></p>
        <p><button onClick={() => changeState({ prevMemoizedCallback: memoizedCallback, prevUnMemoizedCallback: unMemoizedCallback })}>update State</button></p>
      </>
    );
};

render(<App />, document.getElementById('root'));
6
Barbu Barbu