自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

函數(shù)組件和函數(shù)式編程有關(guān)系么?

開(kāi)發(fā) 前端
?「函數(shù)組件」并不是「函數(shù)式編程」在React?中的具體實(shí)現(xiàn),而是React?的設(shè)計(jì)理念UI = fn(snapshot)落地的最好載體。

大家好,我卡頌。

長(zhǎng)期使用React的同學(xué)應(yīng)該知道,React中存在兩種組件:

  • Class Component,類組件
  • Function Component,函數(shù)組件

既然提到「類」和「函數(shù)」,那么很自然的,我們會(huì)進(jìn)一步思考:

  • 類組件和OOP(面向?qū)ο缶幊蹋┯嘘P(guān)系么?
  • 函數(shù)組件和FP(函數(shù)式編程)有關(guān)系么?

畢竟,如果類組件和OOP有關(guān),那么OOP中的思想(繼承、封裝、多態(tài)...)也能指導(dǎo)類組件的業(yè)務(wù)開(kāi)發(fā)(函數(shù)組件與FP的關(guān)系同理)。換言之,我們可以直接用這些編程范式的最佳實(shí)踐指導(dǎo)React項(xiàng)目開(kāi)發(fā)。

那么,「函數(shù)組件」和「函數(shù)式編程」究竟是什么關(guān)系呢?本文會(huì)圍繞這個(gè)話題展開(kāi)講解。

編程范式與DSL

首先,我們應(yīng)該明確,「框架語(yǔ)法」本質(zhì)是一種DSL(領(lǐng)域相關(guān)語(yǔ)言),他是為了「某個(gè)特定領(lǐng)域的開(kāi)發(fā)」量身定制的。

比如,React作為一款針對(duì)「view開(kāi)發(fā)」的DSL,雖然不同的view使用的框架不同,比如:

  • 對(duì)于web,框架為ReactDOM。
  • 對(duì)于小程序,框架為Taro。
  • 對(duì)于原生開(kāi)發(fā),字節(jié)內(nèi)部有個(gè)叫React Lynx的框架。

但這些框架都大體遵循同一套DSL(React語(yǔ)法),這套DSL并不屬于某一種編程范式,而應(yīng)該被視為「不同編程范式中,更符合view開(kāi)發(fā)的語(yǔ)言特性的集合」。

所以,作為React DSL的一部分,函數(shù)組件可以體現(xiàn)OOP的思想,類組件也能體現(xiàn)FP的思想。只要這些思想有利于「view開(kāi)發(fā)」,就可以納入DSL的語(yǔ)法中。

比如,下面的函數(shù)組件Header,是由WelcomeMessage與LogoutButton組件組合而成,這是OOP中的「組合優(yōu)于繼承」思想:

function Header(props) {
  return (
    <div>
      <WelcomeMessage name={props.name} />
      <LogoutButton onClick={props.onLogout} />
    </div>
  );
}

再比如,下面的類組件Cpn中,要改變狀態(tài)count,并不是通過(guò)突變(類似this.state.count++),而是調(diào)用this.setState,傳入不可變數(shù)據(jù):

class Cpn extends React.Component {
  // ...
  onClick() {
    const count = this.state.count;
    this.setState({count: count + 1});
  }
  render() {
    // ...
  }
}

「使用不可變數(shù)據(jù)」屬于FP中的思想。

所以,當(dāng)我們要深入了解某個(gè)React特性時(shí),應(yīng)該以如下順序遞進(jìn)的思考:

  • React的開(kāi)發(fā)理念是什么?
  • 為了實(shí)現(xiàn)這套理念,吸收了哪些編程范式中的思想。
  • 這些思想如何在React中落地。

如果我們用上述思考過(guò)程研究「函數(shù)組件與函數(shù)式編程的關(guān)系」,會(huì)發(fā)現(xiàn):

  • 函數(shù)組件屬于落地的產(chǎn)物(上述思考的第三步)。
  • 函數(shù)式編程屬于編程范式(上述思考的第二步)。

這就是兩者的關(guān)系 —— 函數(shù)組件屬于多種編程范式(主要是OOP與FP)在React中最終的落地產(chǎn)物,其中借鑒了一部分FP的思想。

我們不應(yīng)該將函數(shù)組件單純視為FP在React中的具象體現(xiàn)。

那么,函數(shù)組件究竟是如何演進(jìn)而來(lái)的呢?

函數(shù)組件的演進(jìn)

讓我們按照上述三步演進(jìn)順序思考。首先,React的開(kāi)發(fā)理念踐行了如下公式(即:UI是數(shù)據(jù)快照經(jīng)過(guò)函數(shù)映射而來(lái)):

UI = fn(snapshot)

要落地這個(gè)理念,有兩個(gè)要素需要實(shí)現(xiàn):

  • 數(shù)據(jù)快照
  • 函數(shù)映射

在這里,F(xiàn)P中「不可變數(shù)據(jù)」更適合作為「數(shù)據(jù)快照」的載體,所以React中狀態(tài)是不可變的,因?yàn)闋顟B(tài)的本質(zhì)是快照。

而「函數(shù)映射」的載體則沒(méi)有特殊要求。在React中,每次觸發(fā)更新,所有組件都會(huì)重新render,render的過(guò)程就是「函數(shù)映射」的過(guò)程,輸入是props與state,輸出是JSX。

與React相對(duì)的,Vue中組件則更符合OOP的理念,考慮如下App組件:

const App = {
  setup(initialProps) {
    const count = reactive({count: 0})
    const add = () => { count.value++ }
    return {count, add}
  }
  template: "...省略"
}

組件的setup方法只會(huì)在初始化時(shí)執(zhí)行一次,后續(xù)觸發(fā)更新時(shí)操作的都是同一個(gè)閉包中的數(shù)據(jù)。這里面的閉包就是OOP思想中的實(shí)例。

既然React對(duì)「函數(shù)映射」的載體沒(méi)有特殊要求,那么類組件、函數(shù)組件都是可以的。

那為什么函數(shù)組件最終替代了類組件成為React開(kāi)發(fā)的主流呢?很多同學(xué)認(rèn)為「函數(shù)組件的Hooks可以更好的復(fù)用邏輯」這一點(diǎn),是函數(shù)組件優(yōu)于類組件的主要原因。

但實(shí)際上,基于裝飾器的類開(kāi)發(fā)模式早已被驗(yàn)證是優(yōu)秀的邏輯復(fù)用模式,類組件配合TS裝飾器的模式是行得通的。

主要原因還是 —— 函數(shù)組件能夠更好的落地UI = fn(snapshot)這一理念。

剛才說(shuō)過(guò),公式中的snapshot是「快照」的含義。在React中,快照主要包括三類數(shù)據(jù):

  • state
  • props
  • context

對(duì)于同一個(gè)組件,根據(jù)公式UI = fn(snapshot),相同的快照輸入應(yīng)該獲得相同輸出(JSX)。

但狀態(tài)更新也可能觸發(fā)「副作用」,比如請(qǐng)求數(shù)據(jù)、操作DOM...

在類組件中,這些「副作用」邏輯被分散在各個(gè)生命周期鉤子函數(shù)中,React無(wú)法掌控。

而在函數(shù)組件中:

  • 副作用受限在useEffect中。每次render,React都會(huì)保證上次的副作用效果已經(jīng)被清除(通過(guò)useEffect回調(diào)的返回值函數(shù))
  • ref的傳播也需要借由forwardRef,這進(jìn)一步限制了ref可能的影響范圍。
  • 數(shù)據(jù)請(qǐng)求的副作用被交給Suspense處理,考慮下面組件:
function UserList({id}) {
  // 異步請(qǐng)求數(shù)據(jù)
  const data = use(fetchUser(id));
  
  // ...
}

使用時(shí):

<Suspense fallback={<div>加載中...</div>}>
  <UserList id={1}/>
</Suspense>

總而言之,使用函數(shù)組件時(shí),所有副作用都處于一種「受到管控」的狀態(tài),可以盡可能保證每次更新時(shí)「相同的快照輸入,獲得相同的JSX輸出」,所以函數(shù)組件在React中才會(huì)發(fā)揚(yáng)光大。

同時(shí),這也契合了FP中的純函數(shù)思想。

總結(jié)

「函數(shù)組件」并不是「函數(shù)式編程」在React中的具體實(shí)現(xiàn),而是React的設(shè)計(jì)理念UI = fn(snapshot)落地的最好載體。

在React中,還吸收了其他編程范式中的優(yōu)秀思想。FP只是其中影響React最深的一種。畢竟,一切落地都是為了踐行最初的設(shè)計(jì)理念。

責(zé)任編輯:姜華 來(lái)源: 魔術(shù)師卡頌
相關(guān)推薦

2012-03-21 09:30:11

ibmdw

2013-09-09 09:41:34

2011-10-19 15:47:13

2017-06-08 14:25:46

Kotlin函數(shù)

2023-05-06 07:27:47

2023-10-07 00:01:02

Java函數(shù)

2022-07-07 09:03:36

Python返回函數(shù)匿名函數(shù)

2011-03-08 15:47:32

函數(shù)式編程

2016-10-31 20:46:22

函數(shù)式編程Javascript

2020-09-24 10:57:12

編程函數(shù)式前端

2025-03-11 10:00:20

Golang編程函數(shù)

2023-12-14 15:31:43

函數(shù)式編程python編程

2011-08-24 09:13:40

編程

2022-09-22 08:19:26

WebFlux函數(shù)式編程

2020-09-23 16:07:52

JavaScript函數(shù)柯里化

2020-05-26 21:17:28

函數(shù)式編程純函數(shù)

2020-05-26 16:27:58

函數(shù)孩子編程

2010-03-11 10:34:22

Scala

2020-09-23 07:50:45

Java函數(shù)式編程

2012-09-21 09:21:44

函數(shù)式編程函數(shù)式語(yǔ)言編程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)