摘要:可以看到,組件其實是一個對象,并不是一個真實的。引入了一種新的原始數據類型,表示獨一無二的值。你好,這里是組件可以看到,都發生了變化,值就是我們賦予的值,中嵌套了屬性。根據最初的代碼,我們組件用到了。
前言
react使用也有一段時間了,大家對這個框架褒獎有加,但是它究竟好在哪里呢?
讓我們結合它的源碼,探究一二?。ó斍霸创a為react16,讀者要對react有一定的了解)
根據react官網上的例子,快速構建react項目
npx create-react-app my-app cd my-app npm start
打開項目并跑起來以后,暫不關心項目結構及語法糖,看到App.js里,這是一個基本的react組件
import React, { Component } from "react"; import logo from "./logo.svg"; import "./App.css"; class App extends Component { render() { return (); } } export default App; console.log(Edit
src/App.js
and save to reload.)
可以看到,
ES6 引入了一種新的原始數據類型Symbol,表示獨一無二的值。有興趣的同學可以去阮一峰老師的ES6入門詳細了解一下
上面有我們很熟悉的props,ref,key,我們稍微修改一下console,看看有什么變化。
console.log() 你好,這里是App組件
可以看到,props,key都發生了變化,值就是我們賦予的值,props中嵌套了children屬性??墒菫槭裁次覀兦度氲氖莇iv,實際上卻是一個對象呢?
打開源碼/node_modules/react
首先打開index.js
"use strict"; if (process.env.NODE_ENV === "production") { module.exports = require("./cjs/react.production.min.js"); } else { module.exports = require("./cjs/react.development.js"); }
可以知道目前用上的是./cjs/react.development.js,直接打開文件。
根據最初的代碼,我們組件
接著找到Component: Component方法,
function Component(props, context, updater) { this.props = props; this.context = context; // If a component has string refs, we will assign a different object later. this.refs = emptyObject; // We initialize the default updater but the real one gets injected by the // renderer. this.updater = updater || ReactNoopUpdateQueue; } Component.prototype.isReactComponent = {}; Component.prototype.setState = function (partialState, callback) { !(typeof partialState === "object" || typeof partialState === "function" || partialState == null) ? invariant(false, "setState(...): takes an object of state variables to update or a function which returns an object of state variables.") : void 0; this.updater.enqueueSetState(this, partialState, callback, "setState"); }; Component.prototype.forceUpdate = function (callback) { this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); };
上面就是一些簡單的構造函數,也可以看到,我們常用的setState是定義在原型上的2個方法。
至此,一個
到此為止了嗎?這看了等于沒看啊,究竟組件是怎么變成div的?render嗎?
可是全局搜索,也沒有一個function是render啊。
原來,我們的jsx語法會被babel編譯的。
這下清楚了,還用到了React.createElement
createElement: createElementWithValidation,
通過createElementWithValidation,
function createElementWithValidation(type, props, children) { ······ var element = createElement.apply(this, arguments); return element; }
可以看到,return了一個element,這個element又是繼承自createElement,接著往下找:
function createElement(type, config, children) { var propName = void 0; // Reserved names are extracted var props = {}; var key = null; var ref = null; var self = null; var source = null; ······ return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props); }
這里又返回了一個ReactElement方法,再順著往下找:
var ReactElement = function (type, key, ref, self, source, owner, props) { var element = { // This tag allows us to uniquely identify this as a React Element $$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // Record the component responsible for creating this element. _owner: owner }; ······ return element; };
誒,這里好像返回的就是element對象,再看我們最初的
驗證一下我們的探索究竟對不對,再每一個方法上我們都打上console,(注意,將App里的子元素全部刪空,利于我們觀察)
React.createElement 、 createElementWithValidation 、 createElement 、 ReactElement,通過這些方法,我們用class聲明的React組件在變成真實dom之前都是ReactElement類型的js對象
createElementWithValidation:
首先校驗type是否是合法的
校驗了props是否符合設置的proptypes
校驗了子節點的key,確保每個數組中的元素都有唯一的key
createElement:
type是你要創建的元素的類型,可以是html的div或者span,也可以是其他的react組件,注意大小寫
config中包含了props、key、ref、self、source等
向props加入children,如果是一個就放一個對象,如果是多個就放入一個數組。
那如果type.defaultProps有默認的props時,并且對應的props里面的值是undefined,把默認值賦值到props中
也會對key和ref進行校驗
ReactElement:
ReactElement就比較簡單了,創建一個element對象,參數里的type、key、ref、props、等放進去,然后return了。最后調用Object.freeze使對象不可再改變。
組件的掛載我們上面只是簡單的探究了
ReactDOM.render(, document.getElementById("root"));
我們接著用babel編譯一下:
原來ReactDOM.render調用的是render方法,一樣,找暴露出來的接口。
var ReactDOM = { ······ render: function (element, container, callback) { return legacyRenderSubtreeIntoContainer(null, element, container, false, callback); }, ······ };
它返回的是一個legacyRenderSubtreeIntoContainer方法,這次我們直接打上console.log
這是打印出來的結果,
legacyRenderSubtreeIntoContainer
這個方法除主要做了兩件事:
清除dom容器元素的子元素
while (rootSibling = container.lastChild) { { if (!warned && rootSibling.nodeType === ELEMENT_NODE && rootSibling.hasAttribute(ROOT_ATTRIBUTE_NAME)) { warned = true; } } container.removeChild(rootSibling); }
創建ReactRoot對象
源碼暫時只讀到了這里,關于React16.1~3的新功能,以及新的生命周期的使用和原理、Fiber究竟是什么,我們將在后續文章接著介紹。
廣而告之本文發布于薄荷前端周刊,歡迎Watch & Star ★,轉載請注明出處。
歡迎討論,點個贊再走吧 ????? ~文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98848.html
摘要:本篇開始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結構如下經過編譯后,生成如下代碼構建頂層包裝組件跟普通元素渲染一樣,第一步先會執行創建為的。調用順序已在代碼中注釋。先看圖,這部分內容將在下回分解 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非...
摘要:前言的基本概念組件的構建方法以及高級用法這背后的一切如何運轉深入內部的實現機制和原理初探源碼代碼組織結構包含一系列的工具方法插件包含一系列同構方法包含一些公用或常用方法如等包含一些測試方法等包含一些邊界錯誤的測試用例是代碼的核心部分它包含了 前言 React的基本概念,API,組件的構建方法以及高級用法,這背后的一切如何運轉,深入Virtual DOM內部的實現機制和原理. 初探Rea...
摘要:依賴注入和控制反轉,這兩個詞經常一起出現。一句話表述他們之間的關系依賴注入是控制反轉的一種實現方式。而兩者有大量的代碼都是可以共享的,這就是依賴注入的使用場景了。下一步就是創建具體的依賴內容,然后注入到需要的地方這里的等于這個對象。 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級...
摘要:在學習源碼的過程中,給我幫助最大的就是這個系列文章,于是決定基于這個系列文章談一下自己的理解。到此為止,首次渲染就完成啦總結從啟動到元素渲染到頁面,并不像看起來這么簡單,中間經歷了復雜的層級調用。 前言 React 是一個十分龐大的庫,由于要同時考慮 ReactDom 和 ReactNative ,還有服務器渲染等,導致其代碼抽象化程度很高,嵌套層級非常深,閱讀其源碼是一個非常艱辛的過...
摘要:技術上來說,當方法被調用后或者發生改變后,方法都會被調用。下一步,會設置為。之后,檢測當前更新是否由更新引起的。這是因為,使用是導致組件持久化更新,而會被方法的返回值重新賦值。 接上文, React流程圖:https://bogdan-lyashenko.gith... 更新組件 關于組件的更新,我們先看下代碼里的注釋: 對于已掛載組件的更新過程,React會首先調用component...
閱讀 2941·2023-04-26 01:52
閱讀 3468·2021-09-04 16:40
閱讀 3629·2021-08-31 09:41
閱讀 1764·2021-08-09 13:41
閱讀 556·2019-08-30 15:54
閱讀 2960·2019-08-30 11:22
閱讀 1612·2019-08-30 10:52
閱讀 948·2019-08-29 13:24