搜尋
首頁web前端js教程React 內部機制探秘
React 內部機制探秘Oct 25, 2017 pm 03:06 PM
react內部探秘

React 內部機制探秘 - React Component 和 Element

這篇文章比較偏基礎,但是對入門 React 內部機制和實作原理卻至關重要。算是為以後深入解讀的一個入門,如果您已經非常清楚:

React Component Render => JSX => React.createElement => Virtual Dom

#的流程,可以直接略過此文。

Google工程師一個風騷的問題

在幾個月前,Google的前端開發專家Tyler McGinnis 在其個人twitter 帳號上發布了這樣一條推文,引發了對React 組件的討論。

React 內部機制探秘

他拋出的問題是 :如上述程式碼,React 元件 Icon 直接出現在程式碼中,到底算什麼?

提供的選項有:

  • A. Component Declaration 元件宣告

  • B. Component Invocation 元件調用

  • C. Component Instantiation 元件實例化

  • #D. Using a Component 單純地使用元件

#有趣的是,參與回答的開發者中:

  • ##有15% 選擇了A 項;

  • 有8% 選擇了B 項;

  • 有45% 選擇了C 項;

  • 有32% 選擇了D 項;

#對React 開發經驗豐富的前端工程師來說,這個問題其實很好理解。它的關鍵在於:

真正明白 React Element 和 React Components,以及 JSX 抽象層是如連通 React 的。

當然也需要明白一些淺顯的 React 內部工作機制。

這篇文章,就帶領大家研究這個 JSX 抽象層的奧秘和

React Reconciliation 流程。

React 和 React Element 到底是什麼?
  • 讓我們回到最初,思考一下最原始的問題,React 到底是什麼?

    簡而言之,
  • React is a library for building user interfaces.

React 是一個建構視圖層的類別庫(框架. ..whatever...)。不管 React 本身如何複雜,不管其生態如何龐大,

建立視圖

始終是他的核心。記住這個訊息,我們即將進入今天的第一個概念 —

React Element

  • 簡單地說,React Element 描述了「你想」在螢幕上看到的事物。

    抽像地說,React Element 元素是一個描述了 Dom Node 的物件。
  • 請注意我的用詞 — “

    描述

    ”,因為 React Element 並不是你在螢幕上看到的真實事物。相反地​​,他是一個描述真實事物的集合。存在的就是合理的,我們看來看看 React Element 存在的意義,以及為什麼會有這樣一個概念:
  • JavaScript 物件很輕量。用物件來作為React Element,那麼React 可以輕鬆的創建或銷毀這些元素,而不必去太擔心操作成本;

React 具有分析這些物件的能力,進一步,也具有分析虛擬Dom 的能力。當改變出現時,(比起真實 Dom)更新虛擬 Dom 的效能優勢非常明顯。

為了建立我們描述Dom Node 的物件(或React Element),我們可以使用React.createElement 方法:

const element = React.createElement( 
  'p', 
  {id: 'login-btn'}, 
  'Login'
)

這裡React.createElement 方法接受三個參數:

一個表述標籤名稱的字串(p, span, etc.);

目前React Element 需要具有的屬性;

目前React Element 要表達的內容,或一個子元素。

######上面React.createElement 方法呼叫之後,會回傳一個javascript 物件:###
{ 
  type: 'p', 
  props: { 
    children: 'Login', 
    id: 'login-btn' 
  } 
}
###接著當我們使用ReactDOM.render 方法,這才渲染到真實DOM 之上時,就會得到:###
<p id=&#39;login-btn&#39;>Login</p>
###而這個才是真實的Dom 節點。 ######到目前為止,並沒有什麼很難理解的概念。 ######React Element 深入和React Component######這篇文章我們開篇就介紹了React Element,而並不是像官網或學習資料上來就介紹React Component,我相信你理解了React Element ,理解React Component 就是自然而然的事了。 ######在真正開發時,我們並沒有直接使用 React.createElement,這樣做簡直太無聊了,每個元件都這樣寫一定會瘋掉的。這時候就出現了 React Component,也就是 React 元件。 #########A component is a function or a Class which optionally accepts input and returns a React element.#########沒錯,元件就是一個函式或一個Class(當然Class 也是function),它根據輸入參數,並最終傳回一個React Element,而不需要我們直接手寫無聊的React Element。 ######所以說,實際上我們使用了 React Component 來產生 React Element,這對於開發體驗的提升無疑是巨大的。 ###

这里剖出一个思考题:所有 React Component 都需要返回  React Element 吗?显然是不需要的,那么 return null; 的 React 组件有存在的意义吗,它能完成并实现哪些巧妙的设计和思想?(请关注作者,下篇文章将会专门进行分析、讲解)

从场景实例来看问题

接下来,请看这样一段代码:

function Button ({ onLogin }) { 
  return React.createElement( 
    &#39;p&#39;, 
    {id: &#39;login-btn&#39;, onClick: onLogin}, 
    &#39;Login&#39; 
  )
}

我们定义了一个 Button 组件,它接收 onLogin 参数,并返回一个 React Element。注意 onLogin 参数是一个函数,并最终像 id:'login-btn' 一样成为了这个 React Element 的属性。

直到目前,我们见到了一个 React Element type 为 HTML 标签(“span”, “p”, etc)的情况。事实上,我们也可以传递另一个 React Element :

const element = React.createElement(
  User, 
  {name: &#39;Lucas&#39;},
  null 
)

注意此时 React.createElement 第一个参数是另一个 React Element,这与 type 值为 HTML 标签的情况不尽相同,当 React 发现 type 值为一个 class 或者函数时,它就会先看这个 class 或函数会返回什么样的 Element,并为这个 Element 设置正确的属性。

React 会一直不断重复这个过程(有点类似递归),直到没有 “createElement 调用 type 值为 class 或者 function” 的情况。

我们结合代码再来体会一下:

function Button ({ addFriend }) {
  return React.createElement(
    "button", 
    { onClick: addFriend }, 
    "Add Friend" 
  ) 
} 
function User({ name, addFriend }) { 
  return React.createElement(
    "p", 
    null,
    React.createElement( "p", null, name ),
    React.createElement(Button, { addFriend })
  ) 
}

上面有两个组件:Button 和 User,User 描述的 Dom 是一个 p 标签,这个 p 内,又存在一个 p 标签,这个 p 标签展示了用户的 name;还存在一个 Button。

现在我们来看 User 和 Button 中,React.createElement 返回情况:

function Button ({ addFriend }) { 
  return { 
    type: &#39;button&#39;, 
    props: { 
      onClick: addFriend, 
      children: &#39;Add Friend&#39; 
    } 
  } 
} 
function User ({ name, addFriend }) { 
  return { 
    type: &#39;p&#39;, 
    props: { 
      children: [{ 
        type: &#39;p&#39;,
        props: { children: name } 
      }, 
      { 
       type: Button, 
       props: { addFriend } 
      }]
    }
  }
}

你会发现,上面的输出中,我们发现了四种 type 值:

  • "button";

  • "p";

  • "p";

  • Button

当 React 发现 type 是 Button 时,它会查询这个 Button 组件会返回什么样的 React Element,并赋予正确的 props。

直到最终,React 会得到完整的表述 Dom 树的对象。在我们的例子中,就是:

<p style="margin-bottom: 7px;">{<br/>  type: &#39;p&#39;, <br/>  props: {<br/>    children: [{<br/>      type: &#39;p&#39;,<br/>      props: { children: &#39;Tyler McGinnis&#39; }<br/>    }, <br/>    { <br/>      type: &#39;button&#39;, <br/>      props: { <br/>        onClick: addFriend, <br/>        children: &#39;Add Friend&#39;<br/>      }<br/>     }]<br/>   } <br/>}<br/></p>

React 处理这些逻辑的过程就叫做 reconciliation,那么“这个过程(reconciliation)在何时被触发呢?”

答案当然就是每次 setState 或 ReactDOM.render 调用时。以后的分析文章将会更加详细的说明。

好吧,再回到 Tyler McGinnis 那个风骚的问题上。

React 內部機制探秘

此时我们具备回答这个问题的一切知识了吗?稍等等,我要引出 JSX 这个老朋友了。

JSX 的角色

在 React Component 编写时,相信大家都在使用 JSX 来描述虚拟 Dom。当然,反过来说,React 其实也可以脱离 JSX 而存在。

文章开头部分,我提到 “不常被我们提起的 JSX 抽象层是如何联通 React 的?” 答案很简单,因为 JSX 总是被编译成为 React.createElement 而被调用。一般 Babel 为我们做了 JSX —> React.createElement 这件事情。

再看来先例:

function Button ({ addFriend }) {
  return React.createElement(
    "button",
    { onClick: addFriend },
    "Add Friend" 
   )
} 
function User({ name, addFriend }) { 
  return React.createElement(
    "p",
    null,
    React.createElement( "p", null, name),
    React.createElement(Button, { addFriend })
  )
}

对应我们总在写的 JSX 用法:

function Button ({ addFriend }) { 
  return ( 
    <button onClick={addFriend}>Add Friend</button> 
  )
}
function User ({ name, addFriend }) {
  return ( 
    <p>
     <p>{name}</p>
     <Button addFriend={addFriend}/>
    </p>
  )
}

就是一个编译产出的差别。

最终答案和文末彩蛋

那么,请你来回答“Icon 组件单独出现代表了什么?”

Icon 在 JSX 被编译之后,就有:

React.createElement(Icon, null)

你问我怎么知道这些编译结果的?

或者

你想知道你编写的 JSX 最终编译成了什么样子?

我写了一个小工具,进行对 JSX 的实时编译,放在 Github仓库中,它使用起来是这样子的:

平台一分为二,左边可以写 JSX,右边实时展现其编译结果:

React 內部機制探秘

以及:

React 內部機制探秘

这个工具最核心的代码其实就是使用 babel 进行编译:

let code = e.target.value;
try {
    this.setState({
        output: window.Babel.transform(code, {presets: [&#39;es2015&#39;, &#39;react&#39;]})
        .code,
        err: &#39;&#39;
    })
}
catch(err) {
    this.setState({err: err.message})
}

感兴趣的读者可以去 GitHub 仓库参看源码。

总结

其实不管是 JSX 还是 React Element、React Component 这些概念,都是大家在开发中天天接触到的。有的开发者也许能上手做项目,但是并没有深入理解其中的概念,更无法真正掌握 React 核心思想。

这些内容其实比较基础,但同时又很关键,对于后续理解 React/Preact 源码至关重要。在这个基础上,我会更新更多更加深入的类 React 实现原理剖析,感兴趣的读者可以关注。

我的其他几篇关于React技术栈的文章:

  • 通过实例,学习编写 React 组件的“最佳实践”

  • 從React 綁定this,看JS 語言發展與框架設計

  • 做出Uber行動網頁版還不夠極致效能打造才見真章

  • 解析Twitter前端架構學習複雜場景資料設計

  • React Conf 2017 乾貨總結1: React + ES next = ♥

  • React+Redux打造「NEWS EARLY」單頁應用一個專案理解最前沿技術堆疊真諦

  • 一個react+redux工程實例


#

以上是React 內部機制探秘的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
react中canvas的用法是什么react中canvas的用法是什么Apr 27, 2022 pm 03:12 PM

在react中,canvas用于绘制各种图表、动画等;可以利用“react-konva”插件使用canvas,该插件是一个canvas第三方库,用于使用React操作canvas绘制复杂的画布图形,并提供了元素的事件机制和拖放操作的支持。

react中antd和dva是什么意思react中antd和dva是什么意思Apr 21, 2022 pm 03:25 PM

在react中,antd是基于Ant Design的React UI组件库,主要用于研发企业级中后台产品;dva是一个基于redux和“redux-saga”的数据流方案,内置了“react-router”和fetch,可理解为应用框架。

React是双向数据流吗React是双向数据流吗Apr 21, 2022 am 11:18 AM

React不是双向数据流,而是单向数据流。单向数据流是指数据在某个节点被改动后,只会影响一个方向上的其他节点;React中的表现就是数据主要通过props从父节点传递到子节点,若父级的某个props改变了,React会重渲染所有子节点。

react中为什么使用nodereact中为什么使用nodeApr 21, 2022 am 10:34 AM

因为在react中需要利用到webpack,而webpack依赖nodejs;webpack是一个模块打包机,在执行打包压缩的时候是依赖nodejs的,没有nodejs就不能使用webpack,所以react需要使用nodejs。

react中forceupdate的用法是什么react中forceupdate的用法是什么Apr 19, 2022 pm 12:03 PM

在react中,forceupdate()用于强制使组件跳过shouldComponentUpdate(),直接调用render(),可以触发组件的正常生命周期方法,语法为“component.forceUpdate(callback)”。

react是组件化开发吗react是组件化开发吗Apr 22, 2022 am 10:44 AM

react是组件化开发;组件化是React的核心思想,可以开发出一个个独立可复用的小组件来构造应用,任何的应用都会被抽象成一颗组件树,组件化开发也就是将一个页面拆分成一个个小的功能模块,每个功能完成自己这部分独立功能。

react与vue的虚拟dom有什么区别react与vue的虚拟dom有什么区别Apr 22, 2022 am 11:11 AM

react与vue的虚拟dom没有区别;react和vue的虚拟dom都是用js对象来模拟真实DOM,用虚拟DOM的diff来最小化更新真实DOM,可以减小不必要的性能损耗,按颗粒度分为不同的类型比较同层级dom节点,进行增、删、移的操作。

react和reactdom有什么区别react和reactdom有什么区别Apr 27, 2022 am 10:26 AM

react和reactdom的区别是:ReactDom只做和浏览器或DOM相关的操作,例如“ReactDOM.findDOMNode()”操作;而react负责除浏览器和DOM以外的相关操作,ReactDom是React的一部分。

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前By尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前By尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
4 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版