>  기사  >  웹 프론트엔드  >  React에서 함수 구성요소와 클래스 구성요소의 차이점은 무엇인가요?

React에서 함수 구성요소와 클래스 구성요소의 차이점은 무엇인가요?

青灯夜游
青灯夜游원래의
2020-12-03 09:58:1620944검색

차이점: 1. 함수 구성 요소는 props 객체를 수신하고 반응 요소를 반환하는 순수 함수입니다. 반면 클래스 구성 요소는 React.Component를 상속하고 반응 요소를 반환하는 렌더링 함수를 생성해야 합니다. 2. 함수 구성 요소에는 수명 주기와 상태가 없지만 클래스 구성 요소에는 있습니다.

React에서 함수 구성요소와 클래스 구성요소의 차이점은 무엇인가요?,

이 문서의 운영 환경: Windows 7 시스템, Dell G3 컴퓨터, 반응 버전 17.0.1.

이 글에서는 함수 컴포넌트와 클래스 컴포넌트의 차이점이 무엇인지, 코딩 시 어떻게 선택해야 하는지 보여드리겠습니다.

구성 요소를 정의하는 가장 쉬운 방법은 JavaScript 함수를 사용하는 것입니다. 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>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>Follow</button>
  }
}

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

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

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

  1. 先点击Follow按钮
  2. 3s
    showMessage() {
        alert('Followed ' + this.props.user);
      }
  3. 이 함수는 props 개체를 수신하고 react를 반환합니다. element
  4. ES6 클래스 구문을 사용하여 구성 요소를 작성할 수도 있습니다.
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>
  }
}

두 버전은 동일하며 출력도 동일합니다. 그렇다면 어떤 구현 방법을 선택해야 할까요? 아래에서 비교해 보겠습니다

🎜1. 문법🎜🎜두 가지의 가장 뚜렷한 차이점은 문법에 있습니다. 함수 구성 요소는 props 객체를 받고 react 요소를 반환하는 순수 함수입니다. 클래스 구성 요소는 React.Component를 상속하고 render 함수를 생성하여 react 요소를 반환해야 합니다. 이는 구현되더라도 더 많은 코드가 필요합니다. 효과는 동일합니다. 🎜🎜자세히 살펴보고 babel7을 사용하여 별도로 번역해 보겠습니다.
함수 컴포넌트 번역 결과: 🎜
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>
  }
}
🎜클래스 컴포넌트 번역 결과: 🎜rrreee🎜클래스 컴포넌트 번역을 볼 수 있습니다. ES5의 경우 코드가 점점 더 길어지지만 이는 코드를 구별하는 주요 요소는 아니며 그냥 이해하면 됩니다. 🎜🎜2. 상태 관리🎜🎜함수 구성 요소는 순수 함수이므로 setState를 사용할 수 없습니다. 컴포넌트(), 이것이 바로 함수 컴포넌트를 상태 비저장 컴포넌트라고 부르는 이유입니다. 🎜🎜구성 요소에서 state를 사용해야 하는 경우 클래스 구성 요소를 생성하거나 state를 상위 구성 요소로 승격한 다음 props 객체는 하위 구성 요소에 전달됩니다. 🎜🎜<strong><span style="font-size: 18px;">3. 라이프 사이클 후크</span></strong>🎜🎜함수 컴포넌트에서는 라이프 사이클 후크를 사용할 수 없으며, 사용할 수 없는 이유 <code>State는 동일하며 모든 수명 주기 후크는 상속된 React.Component에서 나옵니다. 🎜🎜그래서 라이프사이클 후크를 사용하려면 클래스 구성요소를 사용해야 합니다. 🎜🎜참고: react16.8 버전에는 hooks가 추가되어 useState 후크를 사용하여 기능을 관리할 수 있습니다. 구성 요소가 상태인 경우 useEffect 후크를 사용하여 수명 주기 기능을 사용합니다. 따라서 점 2와 3은 차이점이 아닙니다. 이번 개정판을 보면 저자가 함수 컴포넌트에 더 많은 중요성을 부여하고 있음을 알 수 있으며 react 팀은 react의 후속 버전에서 함수 컴포넌트의 성능이 향상될 것이라고 언급했습니다. > . 🎜🎜4. 호출 방법🎜🎜SayHi가 함수인 경우 React는 이를 호출해야 합니다: 🎜rrreee🎜SayHi가 클래스인 경우 React는 먼저 new 연산자를 사용해야 합니다. 인스턴스화한 다음 방금 인스턴스를 생성한 render 메서드를 호출합니다. 🎜rrreee🎜상상할 수 있듯이 함수 구성 요소를 다시 렌더링하면 구성 요소 메서드를 다시 호출하여 새 인스턴스를 반환합니다. react 요소, 클래스 구성 요소는 새 구성 요소 인스턴스를 new 다시 렌더링한 다음 render 클래스 메서드를 호출하여 react 요소, 클래스 구성 요소 <code>this가 가변적인 이유🎜🎜5. 렌더링 중에 값을 가져옵니다. 🎜🎜이것이 가장 큰 차이점이지만 사람들은 종종 무시합니다. 🎜🎜다음 구성 요소를 고려하세요. 🎜rrreee🎜 UserProfile 구성 요소는 매우 간단합니다. setTimeout을 사용하여 네트워크를 시뮬레이션하는 Follow 버튼만 있으면 됩니다. 요구. 사용자가 이 버튼을 클릭하면 경고 상자가 나타납니다. props.user'Dan'인 경우 3초 후에 'Followed Dan'이 표시됩니다. 🎜🎜수업에서는 어떻게 작성하나요? 순진한 번역은 다음과 같습니다: 🎜rrreee🎜 이 두 코드 조각이 동일하다고 생각하는 것이 일반적입니다. 사람들은 종종 이러한 패턴 간에 의미를 인식하지 못한 채 자유롭게 리팩터링합니다. 🎜🎜그러나 이 두 코드 조각은 완전히 다릅니다. 잘 살펴보세요. 차이점이 보이나요? 🎜🎜 다음 순서로 팔로우 버튼을 작동하세요: 🎜
    🎜먼저 팔로우 버튼을 클릭하세요 🎜🎜3초 전에 드롭다운 선택을 변경하세요 코드> 항목 옵션🎜🎜팝업 경고 상자의 내용을 읽어보세요🎜🎜🎜함수 구성 요소와 클래스 구성 요소 사이에 차이가 있음을 알 수 있습니다.🎜

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

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

    React에서 함수 구성요소와 클래스 구성요소의 차이점은 무엇인가요?

    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中定义函数而不是使用类方法,那么还有使用类的必要性?

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

위 내용은 React에서 함수 구성요소와 클래스 구성요소의 차이점은 무엇인가요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.