web-dev-qa-db-fra.com

Fonction à l'intérieur du composant fonctionnel dans React hooks - Performance

Besoin d'une suggestion pour avoir une fonction dans un composant fonctionnel dans react Hooks.

Pour autant que j'ai fait des recherches, beaucoup disent que c'est une mauvaise pratique car cela crée une fonction imbriquée/intérieure chaque fois que nous appelons un nouveau rendu. Après avoir fait une analyse,

J'ai trouvé que nous pouvons utiliser onClick={handleClick.bind(null, props)} sur l'élément et placer la fonction en dehors du composant fonctionnel.

Exemple:

const HelloWorld = () => {
  function handleClick = (event) => {
    console.log(event.target.value);
  }

  return() {
    <>
        <input type="text" onChange={handleClick}/>
    </>
  }
}

Veuillez indiquer s'il existe un autre moyen.

Merci d'avance.

9
John Samuel

Ne t'en fais pas

Ne vous inquiétez pas de créer de nouvelles fonctions sur chaque rendu. Ce n'est que dans les cas Edge que cela entrave vos performances. Les gestionnaires onClick ne sont pas de ceux-là, alors créez simplement une nouvelle fonction sur chaque rendu.

Cependant, lorsque vous devez vous assurer que vous utilisez la même fonction à chaque fois, vous pouvez utiliser seCallaback

Pourquoi ne pas utiliser useCallback pour onClick

Voici une raison pour laquelle vous ne devriez pas vous embêter avec les gestionnaires useCallback pour onClick (et la plupart des autres gestionnaires d'événements).

Considérez les extraits de code suivants, un sans useCallback:

function Comp(props) {
  return <button onClick={() => console.log("clicked", props.foo)}>Text</Button>
}

et un avec useCallback:

function Comp(props) {
  const onClick = useCallback(() => {
    console.log("clicked", props.foo)
  }, [props.foo])

  return <button onClick={onClick}>Text</Button>
}

La seule différence dans ce dernier est que React doen doit changer le onClick sur votre bouton si props.foo reste le même. Changer le rappel est une opération très bon marché , et cela ne vaut pas la peine de compliquer votre code pour l'amélioration théorique des performances qu'il donne.

En outre, il convient de noter que une nouvelle fonction est toujours créée sur chaque rendu même lorsque vous utilisez useCallback, mais useCallback renverra l'ancien tant que les dépendances passées comme second argument ne seront pas modifiées.

Pourquoi utiliser useCallback

Le point d'utilisation de useCallback est que si vous comparez deux fonctions avec l'égalité de référence, fn === fn2 n'est vrai que si fn et fn2 pointe vers la même fonction en mémoire. Peu importe si les fonctions faites les mêmes.

Ainsi, si vous avez une mémoisation ou si vous n'exécutez du code que lorsque la fonction change, il peut être utile d'utiliser useCallback pour réutiliser la même fonction.

Par exemple, React les hooks comparent les anciennes et les nouvelles dépendances, probablement en utilisant Object.is .

Un autre exemple est React.PureComponent , qui ne sera rendu que lorsque les accessoires ou l'état auront changé. Cela peut être utile pour les composants qui utilisent beaucoup de ressources pour le rendu. Passer par exemple un nouveau onClick vers un PureComponent sur chaque rendu entraînera un nouveau rendu à chaque fois.

5
ArneHugo

Vous pouvez utiliser la fonction useCallback:

const HelloWorld = ({ dispatch }) => {
  const handleClick = useCallback((event) => {
    dispatch(() => {console.log(event.target.value)}0;
  })

  return() {
    <>
        <input type="name" onChange={handleClick}/>
    </>
  }
}

useCallback renverra une version mémorisée du rappel qui ne change que si l'une des dépendances a changé. Ceci est utile lors du passage de rappels à des composants enfants optimisés qui s'appuient sur l'égalité de référence pour éviter des rendus inutiles (par exemple, shouldComponentUpdate).

Pour plus de détails, visitez leur lien de référence: React useCallback


L'ancienne méthode a également deux options.

Première solution: passer la fonction votre handleClick à votre composant fonctionnel.

const HelloWorld = (props) => {

  return() {
    <>
        <input type="name" onChange={props.handleClick}/>
    </>
  }
}

Deuxième solution: définir votre fonction en dehors de votre composant fonctionnel.

4
Alireza HI

beaucoup disent que c'est une mauvaise pratique car cela crée une fonction imbriquée/intérieure à chaque fois que nous appelons un nouveau rendu

Non, les fonctions/fermetures internes sont si courantes qu'elles ne posent aucun problème. Le moteur peut fortement les optimiser.

Le point ici est que vous passez la fonction comme accessoire au composant enfant. Et comme la fonction a été "recréée", elle n'est pas équivalente à la fonction précédente passée, et donc l'enfant fait un nouveau rend (et c'est mauvais pour les performances).

Vous pouvez résoudre ce problème avec useCallback, qui mémorise la référence de la fonction.

3
Jonas Wilms

Selon React Documentation (fin de la partie),

Le problème avec cette dernière syntaxe est qu'un rappel différent est créé à chaque rendu de LoggingButton. Dans la plupart des cas, c'est très bien. Cependant, si ce rappel est passé en tant qu'accessoire aux composants inférieurs, ces composants peuvent effectuer un nouveau rendu supplémentaire. Nous recommandons généralement la liaison dans le constructeur ou l'utilisation de la syntaxe des champs de classe, pour éviter ce type de problème de performances.

Syntaxe des champs de classe:

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

fonction flèche dans la syntaxe de rappel:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      <button onClick={() => this.handleClick()}>
        Click me
      </button>
    );
  }
}
0
Dhruvil21_04