Maison  >  Article  >  interface Web  >  À quoi devez-vous faire attention lorsque vous utilisez React.setState ?

À quoi devez-vous faire attention lorsque vous utilisez React.setState ?

亚连
亚连original
2018-06-20 11:17:551756parcourir

Cet article présente principalement trois points auxquels il faut prêter attention lors de l'utilisation de React.setState. Il met en avant trois points faciles à ignorer pour les novices de React. Il a une certaine valeur de référence. Les amis intéressés peuvent s'y référer. >

Avant-propos

Le titre original de cet article est 3 raisons pour lesquelles j'ai arrêté d'utiliser React.setState , mais je ne suis pas très intéressé par les arguments avancés par l'auteur original, mais les trois points soulevés par l'auteur sont faciles à ignorer pour les novices de React, je ne mentionnerai donc qu'une partie du contenu ici et changerai le titre en trois points auxquels il faut prêter attention lors de l'utilisation de React.setState.

Texte

Pour les novices de React, utiliser setState est une chose très compliquée. Même si vous êtes un développeur React expérimenté, il est très probable que certains bugs surviennent en raison de certains mécanismes de React, comme l'exemple suivant :

Le document explique également lors de l'utilisation de setState Lorsque vous faites cela, à quoi devez-vous faire attention :

Remarque :

Ne modifiez jamais this.state directement, car appeler setState() plus tard peut remplacer le modifications que vous avez apportées

Changement. Traitez cet état comme immuable.

setState() ne modifie pas this.state immédiatement, mais crée une transition d'état qui sera bientôt traitée. Accéder à this.state après avoir appelé cette méthode peut renvoyer la valeur existante.

Les appels à setState n'ont aucune garantie de synchronisation et les appels peuvent être regroupés pour des gains de performances.

setState() déclenchera toujours un redessin à moins que la logique de rendu conditionnel ne soit implémentée dans ShouldComponentUpdate(). Si des objets mutables sont utilisés et que cette logique ne peut pas être implémentée dans ShouldComponentUpdate(), appeler setState() uniquement lorsqu'il existe une différence entre le nouvel état et l'état précédent peut éviter un nouveau rendu inutile.

Pour résumer, lors de l'utilisation de setState, il y a trois problèmes auxquels il faut prêter attention :

1. setState est asynchrone (Note du traducteur : la synchronisation n'est pas garantie)

De nombreux développeurs n'ont pas remarqué que setState est asynchrone au début. Si vous modifiez un état et que vous le visualisez ensuite directement, vous verrez l'état précédent. C'est l'endroit le plus sujet aux erreurs dans setState. Le mot setState n'a pas l'air asynchrone, il peut donc provoquer des bugs si vous l'utilisez sans réfléchir. L'exemple suivant illustre bien ce problème :

class Select extends React.Component {
 constructor(props, context) {
  super(props, context)
  this.state = {
   selection: props.values[0]
  };
 }
 
 render() {
  return (
   <ul onKeyDown={this.onKeyDown} tabIndex={0}>
    {this.props.values.map(value =>
     <li
      className={value === this.state.selection ? &#39;selected&#39; : &#39;&#39;}
      key={value}
      onClick={() => this.onSelect(value)}
     >
      {value}
     </li> 
    )} 
   </ul>
  )
 }
 
 onSelect(value) {
  this.setState({
   selection: value
  })
  this.fireOnSelect()
 }

 onKeyDown = (e) => {
  const {values} = this.props
  const idx = values.indexOf(this.state.selection)
  if (e.keyCode === 38 && idx > 0) { /* up */
   this.setState({
    selection: values[idx - 1]
   })
  } else if (e.keyCode === 40 && idx < values.length -1) { /* down */
   this.setState({
    selection: values[idx + 1]
   }) 
  }
  this.fireOnSelect()
 }
  
 fireOnSelect() {
  if (typeof this.props.onSelect === "function")
   this.props.onSelect(this.state.selection) /* not what you expected..*/
 }
}

ReactDOM.render(
 <Select 
  values={["State.", "Should.", "Be.", "Synchronous."]} 
  onSelect={value => console.log(value)}
 />,
 document.getElementById("app")
)
À première vue, il ne semble y avoir aucun problème avec ce code. La méthode onSelect est appelée dans les deux gestionnaires d'événements. Cependant, il y a un bug dans ce composant Select qui illustre bien le GIF précédent. La méthode onSelect transmet toujours la valeur state.selection précédente, car lorsque fireOnSelect est appelé, setState n'a pas terminé son travail. Je pense que React devrait au moins changer setState en planningState ou faire de la fonction de rappel un paramètre obligatoire.

Ce bug est facile à corriger. Le plus difficile est que vous devez savoir qu'il existe ce problème.

2. setState entraînera un rendu inutile

Le deuxième problème causé par setState est le suivant : chaque appel entraînera un nouveau rendu. Souvent, ces nouveaux rendus sont inutiles. Vous pouvez utiliser printWasted dans les outils de performances React pour voir quand un rendu inutile se produit. Cependant, grosso modo, il existe plusieurs raisons de rendu inutile :

  1. Le nouvel état est en fait le même que le précédent. Ce problème peut généralement être résolu avec ShouldComponentUpdate. Vous pouvez également utiliser le rendu pur ou d'autres bibliothèques pour résoudre ce problème.

  2. Habituellement, l'état modifié est lié au rendu, mais il existe des exceptions. Par exemple, certaines données sont affichées en fonction de certains états.

  3. Troisièmement, certains états n'ont rien à voir avec le rendu. Certains états peuvent être liés à des événements et à des identifiants de minuterie.

3.setState ne peut pas gérer efficacement tous les états des composants

Sur la base du dernier point ci-dessus, tous les états des composants ne sont pas SetState doit être utilisé pour enregistrer et mettre à jour. Les composants complexes peuvent avoir divers états qui doivent être gérés. L'utilisation de setState pour gérer ces états entraînera non seulement de nombreux rendus inutiles, mais entraînera également l'appel constant des hooks de cycle de vie associés, provoquant de nombreux problèmes étranges.

Postface

Dans l'article original, l'auteur recommandait une bibliothèque appelée MobX pour gérer certains états. Je n'ai pas très froid, je ne la présenterai donc pas. Si vous êtes intéressé, vous pouvez lire l'introduction dans l'article original via le lien en haut.

Sur la base des trois points soulevés ci-dessus, je pense que les débutants devraient prêter attention aux points suivants :

setState n'est pas garanti d'être synchronisé

setState n'est pas garanti d'être synchronisé , ce n'est pas garanti. La synchronisation n'est pas garantie. Dites les choses importantes trois fois. La raison pour laquelle il n'est pas dit asynchrone est que setState est également mis à jour de manière synchrone dans certains cas. Vous pouvez vous référer à cet article

Si vous avez besoin d'obtenir la valeur modifiée directement après setState, il existe plusieurs options :

Passez les paramètres correspondants et ne l'obtenez pas via this.state

针对于之前的例子,完全可以在调用 fireOnSelect 的时候,传入需要的值。而不是在方法中在通过 this.state 来获取

使用回调函数

setState 方法接收一个 function 作为回调函数。这个回掉函数会在 setState 完成以后直接调用,这样就可以获取最新的 state 。对于之前的例子,就可以这样:

this.setState({
 selection: value
}, this.fireOnSelect)

使用setTimeout

在 setState 使用 setTimeout 来让 setState 先完成以后再执行里面内容。这样子:

this.setState({
 selection: value
});
setTimeout(this.fireOnSelect, 0);

直接输出,回调函数, setTimeout 对比

componentDidMount(){
  this.setState({val: this.state.val + 1}, ()=>{
   console.log("In callback " + this.state.val);
  });

  console.log("Direct call " + this.state.val);  
  setTimeout(()=>{
   console.log("begin of setTimeout" + this.state.val);
    this.setState({val: this.state.val + 1}, ()=>{
     console.log("setTimeout setState callback " + this.state.val);
    });

   setTimeout(()=>{
    console.log("setTimeout of settimeout " + this.state.val);
   }, 0);

   console.log("end of setTimeout " + this.state.val);
  }, 0);
 }

如果val默认为0, 输入的结果是:

Direct call 0
In callback 1
begin of setTimeout 1
setTimeout setState callback 2
end of setTimeout 2
setTimeout of settimeout 2

和渲染无关的状态尽量不要放在 state 中来管理

通常 state 中只来管理和渲染有关的状态 ,从而保证 setState 改变的状态都是和渲染有关的状态。这样子就可以避免不必要的重复渲染。其他和渲染无关的状态,可以直接以属性的形式保存在组件中,在需要的时候调用和改变,不会造成渲染。

避免不必要的修改,当 state 的值没有发生改变的时候,尽量不要使用 setState 。虽然 shouldComponentUpdate 和 PureComponent 可以避免不必要的重复渲染,但是还是增加了一层 shallowEqual 的调用,造成多余的浪费。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中使用axios实现文件上传

使用gulp如何创建完整的项目流程

在js中如何实现将数组添加到对象中

在jQuery中如何实现动态控制页面元素

在canvas中如何实现轨迹回放功能

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn