React中函数组件与类组件的区别是什么?

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

React中函数组件与类组件的区别是什么?

本文操作环境:windows7系统、Dell G3电脑、react17.0.1版。

在本文中我将向你展示函数组件和类组件有什么不同,并且在编码过程中应该如何选择?

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

import React from 'react'const Welcome = (props) => {  return 

welcome, {props.name}

}export default Welcome

登录后复制

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

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

import React from 'react'class Welcome extends React.Component {  constructor(props) {    super(props)  }  render() {    return 

welcome, {this.props.name}

}}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 

Hello, React

} // React内部 const result = SayHi(props) // »

Hello, React

登录后复制

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

// 你的代码 class SayHi extends React.Component {     render() {         return 

Hello, React

} } // React内部 const instance = new SayHi(props) // » SayHi {} const result = instance.render() // »

Hello, React

登录后复制

可想而知,函数组件重新渲染将重新调用组件方法返回新的react元素,类组件重新渲染将new一个新的组件实例,然后调用render类方法返回react元素,这也说明为什么类组件中this是可变的

5、获取渲染时的值

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

考虑以下组件:

function ProfilePage(props) {  const showMessage = () => {    alert('Followed ' + props.user);  }  const handleClick = () => {    setTimeout(showMessage, 3000);  }  return (      )}

登录后复制

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   }}

登录后复制

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

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

分别按下面的顺序来操作Follow按钮:

先点击Follow按钮在3s之前更改下拉选择项的选项阅读弹出的警告框内容

你会发现函数组件和类组件是有区别的:

函数组件:按上面所列的三个步骤操作时,当用户在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的渲染结果一部分一部分可视化输出。我们的事件处理程序属于具有特定props和state的特定渲染。但是,当回调超时的话,this.props就会打破这种联系。示例中的showMessage方法在回调时没有绑定到任何特定的渲染,因此它会丢失真正的props。

那么我们有没有一种较好的方式可以使用正确的props来修复render和showMessage回调之间的联系。我们可以在事件发生的早期,将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   }}

登录后复制

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

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

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

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

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

登录后复制

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

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

以上就是React中函数组件与类组件的区别是什么?的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2721063.html

(0)
上一篇 2025年3月7日 22:42:08
下一篇 2025年3月7日 21:42:13

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • 为什么react适合做大型项目?

    原因:1、因为大型项目的庞大带来的是代码优化以及性能优化等问题,而react提倡的更细粒度的封装,带来的组件的复用性提高;且更高自由度的编写可以为手动优化性能带来更大的便利性。2、react社区活跃性高,可提供多样性的解决方案和更多的选择。…

    2025年3月7日
    200
  • redux和react有啥区别

    redux和react的区别有:1、redux是一个JavaScript状态容器,而react是Facebook推出的一个用来构建用户界面的JavaScript库;2、redux主要提供状态管理,而react主要用于构建UI等等。 本教程操…

    2025年3月7日
    200
  • 谷歌怎么安装react插件

    谷歌安装react插件的方法:首先依次点击Chrome的“菜单”->“更多工具”->“扩展程序”;然后点击“获取更多扩展程序”打开谷歌在线商店;最后搜索“React Developer Tools”插件并安装即可。 本教程操作环…

    2025年3月7日 编程技术
    200
  • react向数组中追加数据的方法

    具体方法如下: (免费视频教程:react视频教程) 首先渲染一个随机数,使其每间隔一秒变换一次,效果如下: 代码如下: nbsp;html>  数组追加元素       class Xpf extends React.Compone…

    2025年3月7日
    200
  • react怎么mock数据

    react mock数据的方法:首先在public目录下建立【/api/headerList.json】文件;然后加入相关代码【axios.get(‘/api/headerList.json’)】。 本教程操作环境:…

    2025年3月7日
    200
  • react可以引入css吗?

    react可以引入css,方法:1、直接在组件内部使用“style={{css样式}}”来引入css;2、render函数中先声明一个变量保存样式表绑定给style属性,然后引用;3、使用“import ‘css路径&#8217…

    2025年3月7日
    200
  • react修改端口号的方法是什么

    具体步骤如下: (相关推荐:react教程) 首先打开react项目的 package.json文件; 然后i将 scripts中的start键值对 “start”: “react-scripts start” 登录后复制 修改为即可。 “…

    2025年3月7日
    200
  • react中样式冲突怎么解决

    解决react中样式冲突的方法:首先打开相应的代码文件;然后将类名前加上模块名,如将整个组件的样式表CSS类名前加上组件名LoveVideo即可。 本教程操作环境:windows7系统、react17.0.1版本、thinkpad t480…

    2025年3月7日
    200
  • react中怎么获取input的值

    react获取input值的方法:1、通过event对象信息的方式获取input的值,语法如“inputChange(e){…}”;2、使用ref的方式获取input的值,语法如“this.setState({…})…

    2025年3月7日
    200
  • react中怎么传递事件对象

    react中传递事件对象的方法:1、使用“{(e) => this.deleteRow(id, e)}”方式传递;2、通过“{this.deleteRow.bind(this, id)}”方式传递。 本教程操作环境:windows7系…

    2025年3月7日
    200

发表回复

登录后才能评论