React 源码阅读-13_044
React 源码阅读-13
React Element
Function
Object.getOwnPropertyDescriptor()
方法返回指定对象上一个自有属性对应的属性描述符
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
hasValidRef
判断是否有有效的ref
function hasValidRef(config) { if (__DEV__) { if (hasOwnProperty.call(config, 'ref')) { const getter = Object.getOwnPropertyDescriptor(config, 'ref').get; if (getter && getter.isReactWarning) { return false; } } } return config.ref !== undefined; }
hasValidKey
判断是否有有效的 Key
function hasValidKey(config) { if (__DEV__) { if (hasOwnProperty.call(config, 'key')) { const getter = Object.getOwnPropertyDescriptor(config, 'key').get; if (getter && getter.isReactWarning) { return false; } } } return config.key !== undefined; }
https://developer.mozilla.org...
defineKeyPropWarningGetter
function defineKeyPropWarningGetter(props, displayName) { const warnAboutAccessingKey = function() { if (!specialPropKeyWarningShown) { specialPropKeyWarningShown = true; 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, ); } }; warnAboutAccessingKey.isReactWarning = true; Object.defineProperty(props, 'key', { get: warnAboutAccessingKey, configurable: true, }); }
defineRefPropWarningGetter
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, }); }
ReactElement
const ReactElement = function(type, key, ref, self, source, owner, props) { const element = { // 这个标签使我们可以唯一地将其标识为React Element $$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element type: type, key: key, ref: ref, props: props, // 记录负责创建此元素的组件。 _owner: owner, }; if (__DEV__) { //验证标志当前是可变的。我们穿上 //外部后备存储,以便我们可以冻结整个对象。 //可以在WeakMap中实现后,将其替换为WeakMap //常用的开发环境。 element._store = {}; //为了便于比较ReactElement以进行测试,我们使 //验证标志不可枚举(在可能的情况下,应 //包括我们在其中运行测试的所有环境),因此测试框架 //忽略它。 Object.defineProperty(element._store, 'validated', { configurable: false, enumerable: false, writable: true, value: false, }); // self和source是仅DEV的属性。 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; };
export function
jsx
export function jsx(type, config, maybeKey) { let propName; // Reserved names are extracted const props = {}; let key = null; let ref = null; //当前,key可以作为props传播。这导致潜在的 //如果还明确声明了key,则会出现问题(即<div {... props} key =“ Hi” /> //或<div key =“ Hi” {... props} />)。我们要弃用key传值, //但作为中介步骤,我们将对所有内容使用jsxDEV //<div {... props} key =“ Hi” />,因为我们目前无法确定是否 //key已明确声明为未定义。 if (maybeKey !== undefined) { key = '' + maybeKey; } if (hasValidKey(config)) { key = '' + config.key; } if (hasValidRef(config)) { ref = config.ref; } // 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]; } } // Resolve default props if (type && type.defaultProps) { const defaultProps = type.defaultProps; for (propName in defaultProps) { if (props[propName] === undefined) { props[propName] = defaultProps[propName]; } } } return ReactElement( type, key, ref, undefined, undefined, ReactCurrentOwner.current, props, ); }
jsxDev
行为几乎和 jsx
一致,主要就是defineKeyPropWarningGetter
和defineRefPropWarningGetter
的处理
createElement
创建并返回指定类型的新 React 元素。
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; if (config != null) { 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; // 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) { 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, ); }
createFactory
此辅助函数已废弃
export function createFactory(type) { const factory = createElement.bind(null, type); //公开工厂和原型上的类型,以便可以 //易于访问的元素。例如。 `<Foo />.type === Foo`。 //不应将其命名为“ constructor”,因为它可能不是函数 //创建了元素,甚至可能不是构造函数。 //旧版挂钩:将其删除 factory.type = type; return factory; }
cloneElement
以 element
元素为样板克隆并返回新的 React
元素。返回元素的 props 是将新的 props
与原始元素的 props
浅层合并后的结果。新的子元素将取代现有的子元素,而来自原始元素的 Key
和 ref
将被保留。
isValidElement
验证对象是否为 React
元素,返回值为 true
或 false
。
export function isValidElement(object) { // typeof null = object return ( typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE ); }
https://zh-hans.reactjs.org/d...