看下babel編譯結果javascript
首字母是不是大小寫 判斷翻譯成字符串仍是變量組件的原理 html
源碼文件目錄 java
createElement有三個參數 type, config, children。 點擊查看api 文檔
實現的主要思路是: 點擊進入下文代碼 demo 在線編輯地址react
if (config != null) {
// 剔除config中的 key ref self source 屬性 ,並賦予值
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = "" + config.key;
}
self = config._self === undefined ? null : config._self;
source = config.__source === undefined ? null : config.__source;
// 將properties 添加到新的props對象中
// 使用hasOwnProperty.call 爲防止 config對象自定義hasOwnProperty 屬性
// 具體解釋點擊 https://www.jianshu.com/p/95839681776d
// 未知對象用 hasOwnProperty.call 已知對象能夠直接使用 hasOwnProperty
for(propName in config){
if(
hasOwnProperty.call(config,propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
){
props[propName] = config[propName];
}
}
}
複製代碼
// children 處理獲得 props.children
const childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
const childrenArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childrenArray[i] = arguments[i + 2];
}
// freeze 凍結一個對象使其不可修改 且freeze爲淺凍結
// mdn 地址 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childrenArray);
}
}
props.children = childrenArray;
}
複製代碼
// 若是是組件
if (type && type.defaultProps) {
const defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
複製代碼
// __DEV__下warning 在displayName 組件中 key,ref 是不可配置的屬性
if(__DEV__){
if(key || ref){
const displayName =
typeof type === 'function'
? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
複製代碼
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
複製代碼
ReactElement 接收type, key, ref, self, source, owner, props 7各參數api
slef:
當React.createElement被調用時,用來檢測this的來源,以便咱們能夠發出警告。咱們想要擺脫全部者並用箭頭函數替換字符串ref
s,只要this
和全部者是相同的就沒有了改變行爲 source:
一個註解對象 (由轉路器或者其餘人添加)。用來判斷兩個react element元素是否相等 owner:
記錄負責建立此元素的組件數組
const ReactElement = function(type, key, ref, self, source, owner, props) {
const element = {
// $$typeof是區分react Element對象的惟一標識
$$typeof: REACT_ELEMENT_TYPE,
// 屬於元素的內置屬性
type: type,
key: key,
ref: ref,
props: props,
// 記錄負責建立此元素的組件.
_owner: owner,
};
if (__DEV__) {
element._store = {};
Object.defineProperty(element._store, 'validated', {
configurable: false,
enumerable: false,
writable: true,
value: false,
});
// self and source are DEV only properties.
Object.defineProperty(element, '_self', {
configurable: false,
enumerable: false,
writable: false,
value: self,
});
// 爲了測試目的,在兩個不一樣的地方建立的兩個元素應被視爲相等,所以咱們將其隱藏在枚舉中
Object.defineProperty(element, '_source', {
configurable: false,
enumerable: false,
writable: false,
value: source,
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
};
複製代碼
React Component 只是用來幫助咱們承載一些信息的,沒有生命週期等功能的實現promise
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 = {};
複製代碼
Componenet的prototype 掛載方法bash
PureComponent 進行的 淺比較 (shallow equality check)babel
function PureComponent(props, context, updater) {
this.props = props;
this.context = context;
this.refs = emptyObject;
this.updater = updater || ReactNoopUpdateQueue;
}
const pureComponentPrototype = (PureComponent.prototype = new ComponentDummy());
pureComponentPrototype.constructor = PureComponent;
// Avoid an extra prototype jump for these methods.
Object.assign(pureComponentPrototype, Component.prototype);
// PureComponent 與 Component 本文件中代碼上區別是
pureComponentPrototype.isPureReactComponent = true;
複製代碼
三種使用ref的方式dom
import type {RefObject} from 'shared/ReactTypes';
// an immutable object with a single mutable value
export function createRef(): RefObject {
const refObject = {
current: null,
};
if (__DEV__) {
Object.seal(refObject);
}
return refObject;
}
複製代碼
forwardRef 解決了 pure Function 沒有ref實例的問題
forwardRef 返回 React$Node
官網api文檔 Refs 轉發
點擊進入 : 在線代碼demo編輯
點擊進入 Suspense && lazy 使用demo 連接
import React, { Suspense } from "react";
import ReactDOM from "react-dom";
const LazyComp = React.lazy(() => import("./lazy"));
let data = "";
let promise = "";
const requestData = () => {
if (data) return data;
if (promise) throw promise;
promise = new Promise(res => {
setTimeout(() => {
data = "data res";
res();
}, 2000);
});
throw promise;
};
const SuspenseComp = () => {
const data = requestData();
return <div>{data}</div>;
};
const Comp = () => {
return (
<Suspense fallback="loading data"> <SuspenseComp /> <LazyComp /> </Suspense>
);
};
ReactDOM.render(<Comp />, document.getElementById("container")); 複製代碼
Suspense只有等內部全部組件都加載完畢,纔會把fallback的內容去掉,有任何一個組件處於pending狀態,都會加載fallback
下文源代碼中 result
function mapChildren(children, func, context) {
if (children == null) {
return children;
}
const result = [];
mapIntoWithKeyPrefixInternal(children, result, null, func, context);
return result;
}
複製代碼