摘要:僅針對(duì)數(shù)據(jù)屬性描述有效獲取該屬性的訪(fǎng)問(wèn)器函數(shù)。當(dāng)且僅當(dāng)指定對(duì)象的屬性可以被枚舉出時(shí),為。凍結(jié)及其對(duì)象主要目的是為提高測(cè)試環(huán)境下效率,將的一些屬性配置為不可枚舉,進(jìn)行遍歷的時(shí)候跳過(guò)這些屬性。
React系列
React系列 --- 簡(jiǎn)單模擬語(yǔ)法(一)
React系列 --- Jsx, 合成事件與Refs(二)
React系列 --- virtualdom diff算法實(shí)現(xiàn)分析(三)
React系列 --- 從Mixin到HOC再到HOOKS(四)
React系列 --- createElement, ReactElement與Component部分源碼解析(五)
React系列 --- 從使用React了解Css的各種使用方案(六)
因?yàn)橹皩?xiě)過(guò)一些文章分別關(guān)于怎么模擬React語(yǔ)法,React基本知識(shí)和virtualdom diff實(shí)現(xiàn)思路,接下來(lái)就跟著React源碼大概了解一下怎么一個(gè)過(guò)程,只是主邏輯代碼,忽略部分開(kāi)發(fā)環(huán)境的代碼.
以下解析僅限于我當(dāng)時(shí)理解,不一定準(zhǔn)確.
還是用之前的例子
123456
編譯成
React.createElement("div", { className: "num", index: 1 }, React.createElement("span", null, "123456"));createElement
我們看下API的語(yǔ)法
React.createElement( type, [props], [...children] )
創(chuàng)建并返回給定類(lèi)型的新 React element 。
參數(shù) | 描述 |
---|---|
type | 既可以是一個(gè)標(biāo)簽名稱(chēng)字符串,也可以是一個(gè) React component 類(lèi)型(一個(gè)類(lèi)或一個(gè)函數(shù)),或者一個(gè)React fragment 類(lèi)型 |
props | 各種屬性值 |
children | 子元素 |
因?yàn)橛衎abel會(huì)編譯JSX,所以一般很少會(huì)直接調(diào)用這個(gè)方法.
然后我們進(jìn)入找到對(duì)應(yīng)的源碼位置查看代碼 react/packages/react/src/ReactElement.js
/** * Create and return a new ReactElement of the given type. * See https://reactjs.org/docs/react-api.html#createelement */ export function createElement(type, config, children) { let propName; // Reserved names are extracted const props = {}; let key = null; let ref = null; let self = null; let source = null; // 有傳config的情況下 if (config != null) { // 是否有有效的Ref if (hasValidRef(config)) { ref = config.ref; } // 是否有有效的Key if (hasValidKey(config)) { key = "" + config.key; } // 暫時(shí)還沒(méi)聯(lián)系上下文,保存self和source self = config.__self === undefined ? null : config.__self; source = config.__source === undefined ? null : config.__source; // Remaining properties are added to a new props object for (propName in config) { // 符合情況拷貝屬性 if ( hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName) ) { props[propName] = config[propName]; } } } // Children can be more than one argument, and those are transferred onto // the newly allocated props object. const childrenLength = arguments.length - 2; if (childrenLength === 1) { props.children = children; } else if (childrenLength > 1) { const childArray = Array(childrenLength); for (let i = 0; i < childrenLength; i++) { childArray[i] = arguments[i + 2]; } if (__DEV__) { if (Object.freeze) { Object.freeze(childArray); } } props.children = childArray; } // Resolve default props if (type && type.defaultProps) { const defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } } if (__DEV__) { if (key || ref) { // 如果type是函數(shù)說(shuō)明不是原生dom,所以可以取一下幾個(gè)值 const displayName = typeof type === "function" ? type.displayName || type.name || "Unknown" : type; // 定義key屬性的取值器,添加對(duì)應(yīng)警告 if (key) { defineKeyPropWarningGetter(props, displayName); } // 定義ref屬性的取值器,添加對(duì)應(yīng)警告 if (ref) { defineRefPropWarningGetter(props, displayName); } } } return ReactElement( type, key, ref, self, source, ReactCurrentOwner.current, props, ); }
代碼還比較簡(jiǎn)單,可以看出就是傳入?yún)?shù)之后它會(huì)幫你做些特殊處理然后導(dǎo)出給ReactElement方法使用,如果有部分代碼還不知道是干嘛的話(huà)也不用擔(dān)心,下面會(huì)有說(shuō)到
function hasValidRef(config) { // 開(kāi)發(fā)環(huán)境下 if (__DEV__) { // 自身是否含有ref字段 if (hasOwnProperty.call(config, "ref")) { // 獲取它的取值器 const getter = Object.getOwnPropertyDescriptor(config, "ref").get; // 滿(mǎn)足條件的話(huà)為非法ref if (getter && getter.isReactWarning) { return false; } } } // 直接和undefined作比較判斷是否合法 return config.ref !== undefined; } 同上 function hasValidKey(config) { // 開(kāi)發(fā)環(huán)境 if (__DEV__) { if (hasOwnProperty.call(config, "key")) { const getter = Object.getOwnPropertyDescriptor(config, "key").get; if (getter && getter.isReactWarning) { return false; } } } return config.key !== undefined; }
// 初始化標(biāo)記 let specialPropKeyWarningShown, specialPropRefWarningShown; // 定義key的取值器 function defineKeyPropWarningGetter(props, displayName) { const warnAboutAccessingKey = function() { if (!specialPropKeyWarningShown) { specialPropKeyWarningShown = true; // 目測(cè)是警告提示 warningWithoutStack( false, "%s: `key` is not a prop. Trying to access it will result " + "in `undefined` being returned. If you need to access the same " + "value within the child component, you should pass it as a different " + "prop. (https://fb.me/react-special-props)", displayName, ); } }; // 是否已經(jīng)警告過(guò) warnAboutAccessingKey.isReactWarning = true; // 定義key字段 Object.defineProperty(props, "key", { get: warnAboutAccessingKey, configurable: true, }); } // 同上 function defineRefPropWarningGetter(props, displayName) { const warnAboutAccessingRef = function() { if (!specialPropRefWarningShown) { specialPropRefWarningShown = true; warningWithoutStack( false, "%s: `ref` is not a prop. Trying to access it will result " + "in `undefined` being returned. If you need to access the same " + "value within the child component, you should pass it as a different " + "prop. (https://fb.me/react-special-props)", displayName, ); } }; warnAboutAccessingRef.isReactWarning = true; Object.defineProperty(props, "ref", { get: warnAboutAccessingRef, configurable: true, }); }
代碼來(lái)看是開(kāi)發(fā)模式下限制了對(duì)應(yīng)key和ref的取值器,使用時(shí)會(huì)執(zhí)行對(duì)應(yīng)方法進(jìn)行報(bào)錯(cuò)不讓讀取.
至此相關(guān)源碼基本了解了
getOwnPropertyDescriptor上面其中核心方法介紹是這個(gè)
Object.getOwnPropertyDescriptor(obj, prop)
方法返回指定對(duì)象上一個(gè)自有屬性對(duì)應(yīng)的屬性描述符。(自有屬性指的是直接賦予該對(duì)象的屬性,不需要從原型鏈上進(jìn)行查找的屬性)
參數(shù) | 描述 |
---|---|
obj | 需要查找的目標(biāo)對(duì)象 |
prop | 目標(biāo)對(duì)象內(nèi)屬性名稱(chēng) |
返回值 | 如果指定的屬性存在于對(duì)象上,則返回其屬性描述符對(duì)象(property descriptor),否則返回 undefined |
該方法允許對(duì)一個(gè)屬性的描述進(jìn)行檢索。在 Javascript 中, 屬性 由一個(gè)字符串類(lèi)型的“名字”(name)和一個(gè)“屬性描述符”(property descriptor)對(duì)象構(gòu)成。
一個(gè)屬性描述符是一個(gè)記錄,由下面屬性當(dāng)中的某些組成的:
屬性 | 描述 |
---|---|
value | 該屬性的值(僅針對(duì)數(shù)據(jù)屬性描述符有效) |
writable | 當(dāng)且僅當(dāng)屬性的值可以被改變時(shí)為true。(僅針對(duì)數(shù)據(jù)屬性描述有效) |
get | 獲取該屬性的訪(fǎng)問(wèn)器函數(shù)(getter)。如果沒(méi)有訪(fǎng)問(wèn)器, 該值為undefined。(僅針對(duì)包含訪(fǎng)問(wèn)器或設(shè)置器的屬性描述有效) |
set | 獲取該屬性的設(shè)置器函數(shù)(setter)。 如果沒(méi)有設(shè)置器, 該值為undefined。(僅針對(duì)包含訪(fǎng)問(wèn)器或設(shè)置器的屬性描述有效) |
configurable | 當(dāng)且僅當(dāng)指定對(duì)象的屬性描述可以被改變或者屬性可被刪除時(shí),為true。 |
enumerable | 當(dāng)且僅當(dāng)指定對(duì)象的屬性可以被枚舉出時(shí),為 true。 |
然后再看看ReactElement的源碼
/** * Factory method to create a new React element. This no longer adheres to * the class pattern, so do not use new to call it. Also, no instanceof check * will work. Instead test $$typeof field against Symbol.for("react.element") to check * if something is a React Element. * * @param {*} type * @param {*} props * @param {*} key * @param {string|object} ref * @param {*} owner * @param {*} self A *temporary* helper to detect places where `this` is * different from the `owner` when React.createElement is called, so that we * can warn. We want to get rid of owner and replace string `ref`s with arrow * functions, and as long as `this` and owner are the same, there will be no * change in behavior. * @param {*} source An annotation object (added by a transpiler or otherwise) * indicating filename, line number, and/or other information. * @internal */ const ReactElement = function(type, key, ref, self, source, owner, props) { const 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, }; // 開(kāi)發(fā)模式下增改部分屬性 if (__DEV__) { // The validation flag is currently mutative. We put it on // an external backing store so that we can freeze the whole object. // This can be replaced with a WeakMap once they are implemented in // commonly used development environments. element._store = {}; // To make comparing ReactElements easier for testing purposes, we make // the validation flag non-enumerable (where possible, which should // include every environment we run tests in), so the test framework // ignores it. 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, }); // Two elements created in two different places should be considered // equal for testing purposes and therefore we hide it from enumeration. Object.defineProperty(element, "_source", { configurable: false, enumerable: false, writable: false, value: source, }); if (Object.freeze) { Object.freeze(element.props); Object.freeze(element); } } return element; };
整段代碼來(lái)看它是在開(kāi)發(fā)環(huán)境下對(duì)字段作處理:
創(chuàng)建React元素,設(shè)置對(duì)應(yīng)屬性值
開(kāi)發(fā)環(huán)境下
創(chuàng)建_store屬性并配置其validated的屬性描述符對(duì)象,達(dá)到方便調(diào)試React元素的目的
配置_self的屬性描述符對(duì)象,self和source只是DEV的屬性
配置_source的屬性描述符對(duì)象,出于測(cè)試的目的,應(yīng)該將在兩個(gè)不同位置創(chuàng)建的兩個(gè)元素視為相等的,因此我們將它從枚舉中隱藏起來(lái)。
凍結(jié)element及其props對(duì)象
主要目的是為提高測(cè)試環(huán)境下效率,將element的一些屬性配置為不可枚舉,進(jìn)行遍歷的時(shí)候跳過(guò)這些屬性。
其中REACT_ELEMENT_TYPE是
// The Symbol used to tag the ReactElement type. If there is no native Symbol // nor polyfill, then a plain number is used for performance. var REACT_ELEMENT_TYPE = (typeof Symbol === "function" && Symbol.for && Symbol.for("react.element")) || 0xeac7;
用來(lái)標(biāo)識(shí)這個(gè)對(duì)象是一個(gè)ReactElement對(duì)象,至此Jsx編譯成ReactElement對(duì)象的相關(guān)源碼大概知道了.
React組件創(chuàng)建 createClass16.0.0以后已經(jīng)廢棄,可忽略
ES6類(lèi)繼承從官方例子來(lái)看React.Component
class Welcome extends React.Component { render() { returnHello, {this.props.name}
; } }
從源碼看這個(gè)類(lèi)寫(xiě)法做了什么 react/packages/react/src/ReactBaseClasses.js
const emptyObject = {}; if (__DEV__) { Object.freeze(emptyObject); } /** * Base class helpers for the updating state of a 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 = {};
結(jié)構(gòu)比較簡(jiǎn)單,結(jié)合注釋可以知道只是基本賦值,里面有個(gè)更新器后面再說(shuō),現(xiàn)在先記住是用來(lái)更新State就行了.
/** * Sets a subset of the state. Always use this to mutate * state. You should treat `this.state` as immutable. * * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * There is no guarantee that calls to `setState` will run synchronously, * as they may eventually be batched together. You can provide an optional * callback that will be executed when the call to setState is actually * completed. * * When a function is provided to setState, it will be called at some point in * the future (not synchronously). It will be called with the up to date * component arguments (state, props, context). These values can be different * from this.* because your function may be called after receiveProps but before * shouldComponentUpdate, and this new state, props, and context will not yet be * assigned to this. * * @param {object|function} partialState Next partial state or function to * produce next partial state to be merged with current state. * @param {?function} callback Called after state is updated. * @final * @protected */ Component.prototype.setState = function(partialState, callback) { invariant( typeof partialState === "object" || typeof partialState === "function" || partialState == null, "setState(...): takes an object of state variables to update or a " + "function which returns an object of state variables.", ); this.updater.enqueueSetState(this, partialState, callback, "setState"); };
注釋很長(zhǎng)實(shí)際代碼很短,大概意思就是
不保證this.state會(huì)立即更新,所以調(diào)用方法之后可能獲取的舊數(shù)據(jù)
不保證this.state會(huì)同步運(yùn)行,可能最終他們會(huì)批量組合執(zhí)行,可以提供一個(gè)可選完成回調(diào)當(dāng)更新之后再執(zhí)行
回調(diào)會(huì)在未來(lái)某個(gè)點(diǎn)執(zhí)行,可以拿到最新的入?yún)?state, props, context),不同于this.XX,因?yàn)樗鼤?huì)在shouldComponentUpdate之前接收新的props屬性之后執(zhí)行,此時(shí)還沒(méi)賦值給this.
/** * Forces an update. This should only be invoked when it is known with * certainty that we are **not** in a DOM transaction. * * You may want to call this when you know that some deeper aspect of the * component"s state has changed but `setState` was not called. * * This will not invoke `shouldComponentUpdate`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @param {?function} callback Called after update is complete. * @final * @protected */ Component.prototype.forceUpdate = function(callback) { this.updater.enqueueForceUpdate(this, callback, "forceUpdate"); };
這是強(qiáng)制更新視圖的方法
這應(yīng)該只在確定我們不是在一個(gè)DOM事務(wù)中時(shí)調(diào)用
這應(yīng)該在當(dāng)你知道某些深層嵌套組件狀態(tài)已變但是沒(méi)有執(zhí)行setState的時(shí)候調(diào)用
它不會(huì)執(zhí)行shouldComponentUpdate但會(huì)執(zhí)行componentWillUpdate 和componentDidUpdate生命周期
接著我們看源碼 react/packages/shared/invariant.js做了什么
/** * Use invariant() to assert state which your program assumes to be true. * * Provide sprintf-style format (only %s is supported) and arguments * to provide information about what broke and what you were * expecting. * * The invariant message will be stripped in production, but the invariant * will remain to ensure logic does not differ in production. */ export default function invariant(condition, format, a, b, c, d, e, f) { throw new Error( "Internal React error: invariant() is meant to be replaced at compile " + "time. There is no runtime version.", ); }
使用constant()斷言程序假定為真的狀態(tài),僅用于開(kāi)發(fā),會(huì)從生產(chǎn)環(huán)境中剝離保證不受影響
接下來(lái)我們?cè)倏纯?react/packages/react/src/ReactNoopUpdateQueue.js
/** * This is the abstract API for an update queue. */ const ReactNoopUpdateQueue = { /** * Checks whether or not this composite component is mounted. * @param {ReactClass} publicInstance The instance we want to test. * @return {boolean} True if mounted, false otherwise. * @protected * @final */ isMounted: function(publicInstance) { return false; }, /** * Forces an update. This should only be invoked when it is known with * certainty that we are **not** in a DOM transaction. * * You may want to call this when you know that some deeper aspect of the * component"s state has changed but `setState` was not called. * * This will not invoke `shouldComponentUpdate`, but it will invoke * `componentWillUpdate` and `componentDidUpdate`. * * @param {ReactClass} publicInstance The instance that should rerender. * @param {?function} callback Called after component is updated. * @param {?string} callerName name of the calling function in the public API. * @internal */ enqueueForceUpdate: function(publicInstance, callback, callerName) { warnNoop(publicInstance, "forceUpdate"); }, /** * Replaces all of the state. Always use this or `setState` to mutate state. * You should treat `this.state` as immutable. * * There is no guarantee that `this.state` will be immediately updated, so * accessing `this.state` after calling this method may return the old value. * * @param {ReactClass} publicInstance The instance that should rerender. * @param {object} completeState Next state. * @param {?function} callback Called after component is updated. * @param {?string} callerName name of the calling function in the public API. * @internal */ enqueueReplaceState: function( publicInstance, completeState, callback, callerName, ) { warnNoop(publicInstance, "replaceState"); }, /** * Sets a subset of the state. This only exists because _pendingState is * internal. This provides a merging strategy that is not available to deep * properties which is confusing. TODO: Expose pendingState or don"t use it * during the merge. * * @param {ReactClass} publicInstance The instance that should rerender. * @param {object} partialState Next partial state to be merged with state. * @param {?function} callback Called after component is updated. * @param {?string} Name of the calling function in the public API. * @internal */ enqueueSetState: function( publicInstance, partialState, callback, callerName, ) { warnNoop(publicInstance, "setState"); }, }; export default ReactNoopUpdateQueue;
里面提供了三個(gè)函數(shù),分別是
enqueueForceUpdate: 強(qiáng)制更新隊(duì)列包裝器
enqueueReplaceState: 狀態(tài)替換隊(duì)列包裝器
enqueueSetState: 狀態(tài)更新隊(duì)列包裝器
實(shí)際里面都是調(diào)用同一個(gè)方法warnNoop,設(shè)置首參數(shù)都一樣.
const didWarnStateUpdateForUnmountedComponent = {}; function warnNoop(publicInstance, callerName) { if (__DEV__) { const constructor = publicInstance.constructor; const componentName = (constructor && (constructor.displayName || constructor.name)) || "ReactClass"; const warningKey = `${componentName}.${callerName}`; if (didWarnStateUpdateForUnmountedComponent[warningKey]) { return; } warningWithoutStack( false, "Can"t call %s on a component that is not yet mounted. " + "This is a no-op, but it might indicate a bug in your application. " + "Instead, assign to `this.state` directly or define a `state = {};` " + "class property with the desired state in the %s component.", callerName, componentName, ); didWarnStateUpdateForUnmountedComponent[warningKey] = true; } }
目測(cè)應(yīng)該是給傳入的React組件實(shí)例設(shè)置componentName和KEY, 在里面我們?cè)俅慰吹酵粋€(gè)方法warningWithoutStack,我們直接看看他究竟做了什么. react/packages/shared/warningWithoutStack.js
/** * Similar to invariant but only logs a warning if the condition is not met. * This can be used to log issues in development environments in critical * paths. Removing the logging code for production environments will keep the * same logic and follow the same code paths. */ let warningWithoutStack = () => {}; if (__DEV__) { warningWithoutStack = function(condition, format, ...args) { if (format === undefined) { throw new Error( "`warningWithoutStack(condition, format, ...args)` requires a warning " + "message argument", ); } if (args.length > 8) { // Check before the condition to catch violations early. throw new Error( "warningWithoutStack() currently supports at most 8 arguments.", ); } if (condition) { return; } if (typeof console !== "undefined") { const argsWithFormat = args.map(item => "" + item); argsWithFormat.unshift("Warning: " + format); // We intentionally don"t use spread (or .apply) directly because it // breaks IE9: https://github.com/facebook/react/issues/13610 Function.prototype.apply.call(console.error, console, argsWithFormat); } try { // --- Welcome to debugging React --- // This error was thrown as a convenience so that you can use this stack // to find the callsite that caused this warning to fire. let argIndex = 0; const message = "Warning: " + format.replace(/%s/g, () => args[argIndex++]); throw new Error(message); } catch (x) {} }; } export default warningWithoutStack;
類(lèi)似invariant但是只有不滿(mǎn)足條件的時(shí)候才會(huì)打印出警告.這可以用于在關(guān)鍵路徑中記錄開(kāi)發(fā)環(huán)境中的問(wèn)題.生產(chǎn)環(huán)境下會(huì)移除日志代碼保證正常邏輯.代碼只是一些基本的條件設(shè)定和優(yōu)雅降級(jí)代碼.
還有一個(gè)類(lèi)似的繼承類(lèi)PureComponent,可以用于組件進(jìn)行淺對(duì)比決定是否需要更新
function ComponentDummy() {} ComponentDummy.prototype = Component.prototype; /** * Convenience component with default shallow equality check for sCU. */ function PureComponent(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; 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); pureComponentPrototype.isPureReactComponent = true;
基本代碼和Component相似,也繼承自它的原型.但不繼承其自身的屬性方法.
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/106499.html
摘要:調(diào)用棧是這樣的這里生成的我們將其命名為,它將作為參數(shù)傳入到。整個(gè)的調(diào)用棧是這樣的組件間的層級(jí)結(jié)構(gòu)是這樣的到此為止,頂層對(duì)象已經(jīng)構(gòu)造完畢,下一步就是調(diào)用來(lái)自的方法,進(jìn)行頁(yè)面的渲染了。通過(guò)表達(dá)的結(jié)構(gòu)最終會(huì)轉(zhuǎn)化為一個(gè)純對(duì)象,用于下一步的渲染。 歡迎關(guān)注我的公眾號(hào)睿Talk,獲取我最新的文章:showImg(https://segmentfault.com/img/bVbmYjo); 一、前言...
前言:使用react也有二年多了,一直停留在使用層次。雖然很多時(shí)候這樣是夠了。但是總覺(jué)得不深入理解其背后是的實(shí)現(xiàn)邏輯,很難體會(huì)框架的精髓。最近會(huì)寫(xiě)一些相關(guān)的一些文章,來(lái)記錄學(xué)習(xí)的過(guò)程。 備注:react和react-dom源碼版本為16.8.6 本文適合使用過(guò)React進(jìn)行開(kāi)發(fā),并有一定經(jīng)驗(yàn)的人閱讀。 好了閑話(huà)少說(shuō),我們一起來(lái)看源碼吧寫(xiě)過(guò)react知道,我們使用react編寫(xiě)代碼都離不開(kāi)webpa...
摘要:本篇開(kāi)始介紹自定義組件是如何渲染的。組件將自定義組件命名為,結(jié)構(gòu)如下經(jīng)過(guò)編譯后,生成如下代碼構(gòu)建頂層包裝組件跟普通元素渲染一樣,第一步先會(huì)執(zhí)行創(chuàng)建為的。調(diào)用順序已在代碼中注釋。先看圖,這部分內(nèi)容將在下回分解 前言 React 是一個(gè)十分龐大的庫(kù),由于要同時(shí)考慮 ReactDom 和 ReactNative ,還有服務(wù)器渲染等,導(dǎo)致其代碼抽象化程度很高,嵌套層級(jí)非常深,閱讀其源碼是一個(gè)非...
摘要:既然看不懂,那就看看社區(qū)前輩們寫(xiě)的一些源碼分析文章以及實(shí)現(xiàn)思路吧,又這么過(guò)了幾天,總算是摸清點(diǎn)思路,于是在參考了前輩們的基礎(chǔ)上,實(shí)現(xiàn)了一個(gè)簡(jiǎn)易版的??偨Y(jié)以上就是實(shí)現(xiàn)一個(gè)的總體思路,下節(jié)我們重點(diǎn)放在不同的上。 寫(xiě)在開(kāi)頭 工作中使用react也很長(zhǎng)一段時(shí)間了,雖然對(duì)它的用法,原理有了一定的了解,但是總感覺(jué)停留在表面。本著知其然知其所以然的態(tài)度,我試著去看了react源碼,幾天下來(lái),發(fā)現(xiàn)并不...
摘要:我們先來(lái)看下這個(gè)函數(shù)的一些神奇用法對(duì)于上述代碼,也就是函數(shù)來(lái)說(shuō)返回值是。不管你第二個(gè)參數(shù)的函數(shù)返回值是幾維嵌套數(shù)組,函數(shù)都能幫你攤平到一維數(shù)組,并且每次遍歷后返回的數(shù)組中的元素個(gè)數(shù)代表了同一個(gè)節(jié)點(diǎn)需要復(fù)制幾次。這是我的 React 源碼解讀課的第一篇文章,首先來(lái)說(shuō)說(shuō)為啥要寫(xiě)這個(gè)系列文章: 現(xiàn)在工作中基本都用 React 了,由此想了解下內(nèi)部原理 市面上 Vue 的源碼解讀數(shù)不勝數(shù),但是反觀(guān)...
閱讀 1989·2021-11-25 09:43
閱讀 668·2021-10-11 10:58
閱讀 1744·2019-08-30 15:55
閱讀 1739·2019-08-30 13:13
閱讀 747·2019-08-29 17:01
閱讀 1852·2019-08-29 15:30
閱讀 813·2019-08-29 13:49
閱讀 2184·2019-08-29 12:13