百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>JS教程> React中函数组件与类组件的不同是啥?
分享文章到:

React中函数组件与类组件的不同是啥?

发布时间:12/01 来源:未知 浏览: 关键词:

不同:1、函数组件是一个纯函数,它接收一个props对象返回一个react元素;而类组件需要去继承React.Component并且创立render函数返回react元素。2、函数组件没有生命周期和状态state,而类组件有。

在本文中我将向你展现函数组件和类组件有什么不一样,并且在编码历程中应当怎样选中?

定义一个组件最简便的方式就是使用JavaScript函数:

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

这个函数接收一个props对象并返回一个react元素

你也可以使用ES6 class语法去写一个组件:

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

export default Welcome

这两个版本是等价的,它们具有雷同的输出。那么我们应当去选中哪一种实现方式呢?下面我们来对他们停止比力

1、语法上

两者最明显的不一样就是在语法上,函数组件是一个纯函数,它接收一个props对象返回一个react元素。而类组件需要去继承React.Component并且创立render函数返回react元素,这将会要更多的代码,虽然它们实现的结果雷同。

我们更深入的理解下,使用babel7离别对他们停止转译
函数组件转译结果:

"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;

类组件转译结果:

"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;

可以看到类组件转译成ES5后代码更多更长,但这不是区分它们的主要因素,仅仅理解一下。

2、状态治理

由于函数组件是一个纯函数,你不克不及在组件中使用setState(),这也是为什么把函数组件称作为无状态组件。

假如你需要在你的组件中使用state,你可以选中创立一个类组件或者将state晋升到你的父组件中,然后通过props对象传递到子组件。

3、生命周期钩子

你不克不及在函数组件中使用生命周期钩子,缘由和不克不及使用state一样,所有的生命周期钩子都来自于继承的React.Component中。

因此,假如你想使用生命周期钩子,那么需要使用类组件。

留意:在react16.8版本中增加了hooks,使得我们可以在函数组件中使用useState钩子去治理state,使用useEffect钩子去使用生命周期函数。因此,2、3两点就不是它们的不同点。从这个改版中我们可以看出作者愈加看重函数组件,并且react团队曾说起到在react之后的版本将会对函数组件的机能方面停止晋升。

4、调取方式

假如SayHi是一个函数,React需要调取它:

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

假如SayHi是一个类,React需要先用new操纵符将其实例化,然后调取方才生成实例的render办法:

// 你的代码 
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>

不言而喻,函数组件从新渲染将从新调取组件办法返回新的react元素,类组件从新渲染将new一个新的组件实例,然后调取render类办法返回react元素,这也说明为什么类组件中this是可变的

5、猎取渲染时的值

这一点是他们最大差别,但又常常被人们忽略。

思考以下组件:

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

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

  return (
    <button onClick={handleClick}>Follow</button>
  )
}

UserProfile组件很简便,就一个Follow按钮,该按钮使用了setTimeout模拟网络恳求。会员点击这个按钮之后会弹出一个警告框。假如props.user'Dan',它将在三秒钟后显示'Followed Dan'

我们怎样将其编写为类?天真的翻译大概像这样:

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

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

  render() {
    return <button onClick={this.handleClick.bind(this)}>Follow</button>
  }
}

平常认为这两个代码段是等效的。人们经常在这些模式之间自在重构,而没有留意到它们的含义

但是,这两个代码段是完全不一样的。好好看看他们。你看到不同了吗?

离别按下面的次序来操纵Follow按钮:

  1. 先点击Follow按钮
  2. 3s此前更换下拉选中项的选项
  3. 阅读弹出的警告框内容

你会发明函数组件和类组件是有不同的:

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

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

1.gif

2.gif

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

让我们细心看一下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 onClick={this.handleClick.bind(this)}>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 onClick={handleClick}>Follow</button>
  }
}

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

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有152人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板