Maison  >  Article  >  interface Web  >  Quelle est la différence entre les composants de fonction et les composants de classe dans React ?

Quelle est la différence entre les composants de fonction et les composants de classe dans React ?

青灯夜游
青灯夜游original
2020-12-03 09:58:1620944parcourir

Différences : 1. Un composant de fonction est une fonction pure, qui reçoit un objet props et renvoie un élément de réaction ; tandis qu'un composant de classe doit hériter de React.Component et créer une fonction de rendu pour renvoyer un élément de réaction. 2. Les composants de fonction n'ont pas de cycle de vie ni d'état, contrairement aux composants de classe.

Quelle est la différence entre les composants de fonction et les composants de classe dans React ?,

L'environnement d'exploitation de cet article : système Windows 7, ordinateur Dell G3, version React 17.0.1.

Dans cet article, je vais vous montrer quelle est la différence entre les composants de fonction et les composants de classe, et comment choisir lors du codage ?

La manière la plus simple de définir un composant est d'utiliser la fonction JavaScript :

import React from 'react'
const Welcome = (props) => {
  return <h1>welcome, {props.name}</h1>
}
export default Welcome

Cette fonction reçoit un objet props et renvoie un élément react

Vous pouvez également utiliser la syntaxe ES6 class pour écrire un composant :

import React from 'react'
class Welcome extends React.Component {
  constructor(props) {
    super(props)
  }
  render() {
    return <h1>welcome, {this.props.name}</h1>
  }
}

export default Welcome

Les deux versions sont équivalentes, elles ont le même résultat. Alors, quelle méthode de mise en œuvre choisir ? Comparons-les ci-dessous

1 Syntaxe

La différence la plus évidente entre les deux est qu'en termes de syntaxe, le composant fonction est une fonction pure. , il reçoit un objet props et renvoie un élément react. Le composant de classe doit hériter de React.Component et créer une fonction render pour renvoyer l'élément react, ce qui nécessitera plus de code, bien qu'ils obtiennent le même effet.

Examinons de plus près et utilisons babel7 pour les traduire séparément
Résultats de la traduction des composants de fonction :

"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;

var _react = _interopRequireDefault(require("react"));

var Welcome = function Welcome(props) {
  return _react["default"].createElement("h1", null, "welcome, ", props.name);
};

var _default = Welcome;
exports["default"] = _default;

Résultats de la traduction des composants de classe :

"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports["default"] = void 0;

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));

var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));

var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));

var _react = _interopRequireDefault(require("react"));

var Welcome =
/*#__PURE__*/
function (_React$Component) {
  (0, _inherits2["default"])(Welcome, _React$Component);

  function Welcome(props) {
    (0, _classCallCheck2["default"])(this, Welcome);
    return (0, _possibleConstructorReturn2["default"])(this, (0, _getPrototypeOf2["default"])(Welcome).call(this, props));
  }

  (0, _createClass2["default"])(Welcome, [{
    key: "render",
    value: function render() {
      return _react["default"].createElement("h1", null, "welcome, ", this.props.name);
    }
  }]);
  return Welcome;
}(_react["default"].Component);

var _default = Welcome;
exports["default"] = _default;

Oui. que les composants de classe sont traduits en ES5, le code est de plus en plus long, mais ce n'est pas le principal facteur qui les distingue, il suffit de le comprendre.

2. Gestion de l'état

Le composant fonction étant une fonction pure, vous ne pouvez pas utiliser setState() dans le composant, c'est pourquoi Les composants fonctionnels sont appelés composants sans état.

Si vous devez utiliser state dans votre composant, vous pouvez choisir de créer un composant de classe ou de promouvoir le state vers votre composant parent, puis de le transmettre au composant enfant via l'objet props .

3. Hooks de cycle de vie

Vous ne pouvez pas utiliser de hooks de cycle de vie dans les composants fonctionnels pour les mêmes raisons que vous ne pouvez pas utiliser state, tous Les crochets du cycle de vie proviennent tous de l'héritage React.Component.

Donc, si vous souhaitez utiliser des hooks de cycle de vie, vous devez utiliser des composants de classe.

Remarque : react16.8 a été ajouté dans la version hooks, nous permettant d'utiliser le hook useState pour gérer state dans le composant fonction et d'utiliser le hook useEffect pour utiliser la fonction de cycle de vie. Les points 2 et 3 ne constituent donc pas leurs différences. De cette révision, nous pouvons voir que l'auteur attache plus d'importance aux composants de fonction, et l'équipe react a mentionné que les performances des composants de fonction seront améliorées dans les versions après react.

4. Méthode d'appel

Si SayHi est une fonction, React doit l'appeler :

// 你的代码 
function SayHi() { 
    return <p>Hello, React</p> 
} 
// React内部 
const result = SayHi(props) // » <p>Hello, React</p>

Si SayHi est une classe, React doit d'abord l'instancier à l'aide de l'opérateur new, puis appeler la méthode render qui vient de générer l'instance :

// 你的代码 
class SayHi extends React.Component { 
    render() { 
        return <p>Hello, React</p> 
    } 
} 
// React内部 
const instance = new SayHi(props) // » SayHi {} 
const result = instance.render() // » <p>Hello, React</p>

Comme vous pouvez l'imaginer Comme nous le savons, le nouveau rendu d'un composant de fonction rappellera la méthode du composant pour renvoyer un nouvel élément react, le nouveau rendu d'un composant de classe restituera une nouvelle instance de composant, puis appelez la méthode de classe new pour renvoyer un élément render Cela montre également que Pourquoi react est-il une variable dans les composants de classe this

5. Obtenez la valeur quand ? rendu

C'est leur plus grande différence, mais souvent négligée.

Considérez les composants suivants :

function ProfilePage(props) {
  const showMessage = () => {
    alert('Followed ' + props.user);
  }

  const handleClick = () => {
    setTimeout(showMessage, 3000);
  }

  return (
    <button>Follow</button>
  )
}

Le composant est très simple, juste un bouton UserProfile, qui utilise Follow pour simuler une requête réseau. Une fois que l'utilisateur a cliqué sur ce bouton, une boîte d'avertissement apparaîtra. Si setTimeout est props.user, il affichera 'Dan' après trois secondes. 'Followed Dan'

Comment écrivons-nous cela en classe ? Une traduction naïve pourrait ressembler à ceci :

class ProfilePage extends React.Component {
  showMessage() {
    alert('Followed ' + this.props.user);
  }

  handleClick() {
    setTimeout(this.showMessage.bind(this), 3000);
  }

  render() {
    return <button>Follow</button>
  }
}
Il est courant de penser que ces deux extraits sont équivalents. Les gens refactorisent souvent librement entre ces modèles sans remarquer leur signification

Cependant, ces deux extraits de code sont complètement différents. Regardez-les bien. Voyez-vous la différence ?

Actionnez les boutons

dans l'ordre suivant : Follow

    Cliquez d'abord sur le bouton
  1. Follow
  2. Modifiez les options de la sélection déroulante avant
  3. 3s
  4. Lisez le contenu de la boîte d'avertissement contextuelle
Vous constaterez qu'il existe une différence entre les composants de fonction et les composants de classe :

函数组件:按上面所列的三个步骤操作时,当用户在3s前更改下拉选择框的选项时,h1的用户名会立马改变,而3s后弹出的警告框中的用户名并不会改变

类组件:按上面所列的三个步骤操作时,当用户在3s前更改下拉选择框的选项时,h1中的用户名会立马改变,而3s后弹出的警告框中的用户名也会改变

Quelle est la différence entre les composants de fonction et les composants de classe dans React ?

Quelle est la différence entre les composants de fonction et les composants de classe dans React ?

那么,为什么我们的类示例会这样表现呢?

让我们仔细看一下showMessage类中的方法:

showMessage() {
    alert('Followed ' + this.props.user);
  }

showMessage方法中读取了this.props.user(也是我们要输出的用户名称)。而React中的props是不可变的,但是this是可变的,而且是一直是可变的。这也是类组件中this的目的。React自身会随着时间的推移对this进行修改,以便你可以在render函数或生命周期中读取新的版本。

因此,如果组件在请求重新渲染时,this.props将会改变。showMessage方法会从新的props中读取user。你所看到的效果也正是因为这个原因。

React中的组件,UI在概念上可以理解是程序当前状态的函数,那么事件处理就是让UI的渲染结果一部分一部分可视化输出。我们的事件处理程序属于具有特定propsstate的特定渲染。但是,当回调超时的话,this.props就会打破这种联系。示例中的showMessage方法在回调时没有绑定到任何特定的渲染,因此它会丢失真正的props

那么我们有没有一种较好的方式可以使用正确的props来修复rendershowMessage回调之间的联系。我们可以在事件发生的早期,将this.props传递给超时完成的处理程序来尝试着解决这个问题。这种解决方式属于闭包的范畴。

class ProfilePage extends React.Component {
  showMessage(user) {
    alert('Followed ' + user);
  }

  handleClick() {
    cosnt {user} = this.props
    setTimeout(this.showMessage.bind(this, user), 3000);
  }

  render() {
    return <button>Follow</button>
  }
}

我们使用闭包机制将上一状态的值保存下来待showMessage方法调用。即使this.props发生变化,但并不改变user

这种方法虽然解决我们前面所提到的问题,但是这种方法代码会随着props的个数增加,代码也会变得更加冗余也易于出错。如果我们也需要访问state。如果showMessage调用另一个方法,该方法会读取this.props.somethingthis.state.something。我们又会碰到同样的问题。所以我们必须通过this.props作为showMessage的参数来修复它们之间存在的问题。

但这么做会破坏类提供的特性。也令人难于记住或执行。另外,在handleClick中内联alert中的代码并不能解决更大的问题。我们希望以一种允许代码分解成更多方法的方式来构造代码,同时还可以读取与其相关的render所对应的propsstate

或许,我们可以在类的构造函数中绑定这些方法:

class ProfilePage extends React.Component {
  render() {
    // 获取props
    cosnt props = this.props
    
    // 它们不是类方法
    const showMessage = () => {
        alert('Followed ' + props.user);
    }
    
    const handleClick = () => {
        setTimeout(showMessage, 3000)
    }
    
    return <button>Follow</button>
  }
}

这样一来,函数组件和类组件所达到的效果都一样了。在类组件中可以捕获渲染时的props。效果上看上去是一样了,但看起来怪怪的。如果在类组件中的render中定义函数而不是使用类方法,那么还有使用类的必要性?

更多编程相关知识,请访问:编程课程!!

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