Home >Web Front-end >JS Tutorial >What is the difference between function components and class components in React?

What is the difference between function components and class components in React?

青灯夜游
青灯夜游Original
2020-12-03 09:58:1621017browse

Difference: 1. The function component is a pure function, which receives a props object and returns a react element; while the class component needs to inherit React.Component and create a render function to return a react element. 2. Function components do not have a life cycle and state, but class components do.

What is the difference between function components and class components in React?

The operating environment of this article: windows7 system, Dell G3 computer, react17.0.1 version.

In this article I will show you what is the difference between function components and class components, and how should you choose during coding?

The easiest way to define a component is to use the JavaScript function:

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

This function receives a props object and returns a react Elements

You can also use the ES6 class syntax to write a component:

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

export default Welcome

The two versions are equivalent, they have the same output. So which implementation method should we choose? Let’s compare them below

1. Syntax

The most obvious difference between the two is that in syntax, the function component is a Pure function, which receives a props object and returns a react element. The class component needs to inherit React.Component and create a render function to return the react element. This will require more code, although they achieve the same effect. .

Let’s take a deeper look and use babel7 to translate them respectively
Function component translation results:

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

Class component translation results:

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

You can see that the code after class components are translated into ES5 is more and longer, but this is not the main factor to distinguish them, just understand it.

2. State management

Because the function component is a pure function, you cannot use setState()## in the component #, which is why function components are called stateless components.

If you need to use

state in your component, you can choose to create a class component or promote state to your parent component and then pass propsObject passed to child components.

3. Life cycle hooks

You cannot use life cycle hooks in function components for the same reasons as

stateSimilarly, all life cycle hooks come from inherited React.Component.

So, if you want to use life cycle hooks, you need to use class components.

Note: hooks was added in the react16.8 version, allowing us to use useState hooks in function components To manage state, use the useEffect hook to use the life cycle function. Therefore, points 2 and 3 are not their differences. From this revision, we can see that the author attaches more importance to functional components, and the react team has mentioned that subsequent versions of react will improve the performance of functional components.

4. Calling method

If

SayHi is a function, React Need to call it:

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

SayHi is a class, React needs to be instantiated with the new operator first, and then call just now render method to generate an 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>

As you can imagine, function component re-rendering will re-call the component method to return a new react element, class component Re-render will new a new component instance, and then call the render class method to return the react element, which also explains why this## in the class component # is variable

5. Get the value when renderingThis is their biggest difference, but it is often used People ignore.

Consider the following components:

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

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

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

UserProfile

The component is very simple, just a Follow button, which uses setTimeout Simulate network requests. After the user clicks this button, a warning box will pop up. If props.user is 'Dan', it will display 'Followed Dan' after three seconds. How do we write this as a class? A naive translation might look like this:

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

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

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

It is common to think that these two code snippets are equivalent. People often refactor freely between these patterns without noticing what they mean

However, these two code snippets are completely different.

Take a good look at them. Do you see the difference? Operate the

Follow

buttons in the following order:

First click the
    Follow
  1. buttonin
  2. 3s
  3. Change the options of the drop-down selection beforeRead the content of the pop-up warning box
  4. You will find that there is a difference between function components and class components:

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

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

What is the difference between function components and class components in React?

What is the difference between function components and class components in 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中定义函数而不是使用类方法,那么还有使用类的必要性?

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

The above is the detailed content of What is the difference between function components and class components in React?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn