您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關React中函數組件與類組件有什么區別的內容。小編覺得挺實用的,因此分享給大家做個參考。一起跟隨小編過來看看吧。
區別:1、函數組件是一個純函數,它接收一個props對象返回一個react元素;而類組件需要去繼承React.Component并且創建render函數返回react元素。2、函數組件沒有生命周期和狀態state,而類組件有。
在本文中我將向你展示函數組件和類組件有什么不同,并且在編碼過程中應該如何選擇?
定義一個組件最簡單的方式就是使用JavaScript
函數:
import React from 'react' const Welcome = (props) => { return <h2>welcome, {props.name}</h2> } export default Welcome
這個函數接收一個props
對象并返回一個react
元素
你也可以使用ES6 class
語法去寫一個組件:
import React from 'react' class Welcome extends React.Component { constructor(props) { super(props) } render() { return <h2>welcome, {this.props.name}</h2> } } 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("h2", 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("h2", 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
按鈕:
Follow
按鈕3s
之前更改下拉選擇項的選項你會發現函數組件和類組件是有區別的:
函數組件:按上面所列的三個步驟操作時,當用戶在3s
前更改下拉選擇框的選項時,h2
的用戶名會立馬改變,而3s
后彈出的警告框中的用戶名并不會改變
類組件:按上面所列的三個步驟操作時,當用戶在3s
前更改下拉選擇框的選項時,h2
中的用戶名會立馬改變,而3s
后彈出的警告框中的用戶名也會改變
那么,為什么我們的類示例會這樣表現呢?
讓我們仔細看一下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 <button onClick={this.handleClick.bind(this)}>Follow</button> } }
我們使用閉包機制將上一狀態的值保存下來待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 <button onClick={handleClick}>Follow</button> } }
這樣一來,函數組件和類組件所達到的效果都一樣了。在類組件中可以捕獲渲染時的props
。效果上看上去是一樣了,但看起來怪怪的。如果在類組件中的render
中定義函數而不是使用類方法,那么還有使用類的必要性?
感謝各位的閱讀!關于React中函數組件與類組件有什么區別就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。