What is ReactElement?

JSX const s = '<div>hello <span>wo<span> RLD </span></span></ span></div> React.createElement("div", null, "hello ", React.createElement("span", null, "wo", React.createElement("span", null, "rld") ) ); // Convert react code to AST! [WechatIMG54.jpeg](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/92c22c86342c434f8983691130d098db~tplv-k3u1fbpfcp-wa Termark.image) // ReactElement is the JS object that describes the DOMCopy the code

ReactElement mainly uses Object.defineProperty to set attributes

Object.defineProperty

Syntax Object. DefineProperty (obj, propkey, descriptor)

Describes the properties of the object Descriptor
  • If it is set to false, no description of the property can be modified, and no deletion is allowed. If it is set to true, the property description can be modified and deleted. The default is false;
Var a = object.defineProperty ({},'key',{}); // The default information is different without any additional information. Cannot redefine property: key at Function.defineProperty (<anonymous>) at <anonymous>:1:8 */ Object.defineProperty(a,'key',{configurable:true}) Delete a.kaye // If false is displayed, the deletion failsCopy the code
  • Enumerable: Whether it is enumerable, default is false.
For (var key in a){console.log(key)} // undefined object.keys (a) //Copy the code
  • Value: indicates the value of the attribute
  • Writable: Indicates whether value can be changed. The default value is false
A.key =1 console.log(a) // {key: undefined}Copy the code
  • Get: Access description, return the value of the property, default is undefined
Object.defineProperty(a,'key1',{ configurable:true, enumerable:true, Get (){return '2'}}) console.log(a.key1) // 2 configurable:true, enumerable:true, writable:true get(){return '2'} }) /** VM2292:1 Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object> at Function.defineProperty (<anonymous>) at <anonymous>:1:8 */Copy the code
  • Set: Access description, set the property value, default return undefined
DefineProperty (a,'key1',{{token :true, enumerable:true, works without any additional information, and controls any additional information. get(){return key1Value}, set(newV) {key1Value = newV} })Copy the code
Data descriptor

A descriptor is considered a data descriptor if it does not have any of the keys of value, writable, GET, and set.

Ref and key descriptor for the data, so the react in judging ref and the validity of the key is to use the Object. The getOwnPropertyDescriptor (a, ‘key). Get to judge

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; }Copy the code
Object.freeeze

A frozen object cannot be modified, but the property of the frozen object is an object, and the property can be modified, so the property must be frozen if it does not want to be modified

// ReactElement Returns the frozen Object if (object.freeze) {object.freeze (element.props); // ReactElement returns the frozen Object if (object.freeze) {object.freeze (element.props); Object.freeze(element); }Copy the code

Attribute traversal

  • for… In: Loops through the object’s own and inherited properties (except enumerable is false and Symbol)
For (let prop in config){if(config.hasownProperty (prop) &&! RESERVED_PROPS.hasOwnProperty(prop)){ props[prop] = config[prop] } }Copy the code
  • Keys: Loop through the properties of the Object itself (not including inheritance, Enumerable as false,Symbol)
Object.keys(config).forEach(prop=>{ if(! RESERVED_PROPS.hasOwnProperty(prop)){ props[prop] = config[prop] } })Copy the code
  • Object. GetOwnPropertyNames: iterates Object itself attributes, including enumerable for false (does not contain: inheritance, Symbol)
Object.getOwnPropertyNames(config).forEach(prop=>{ if(! RESERVED_PROPS.hasOwnProperty(prop) && Object.getOwnPropertyDescriptor(config,prop).enumerable){ props[prop] = config[prop] } })Copy the code

Deconstructing the Children parameter

  • Obtain the children parameter through the REST parameter of ES6
// Get children if(res.length>0){if(res.length===1)props. Children = res[0] else props. Children = [...Copy the code
  • Get Children by Arguments
Const children = [].slice.call(arguments,2) if(children.length>0){ if(children.length===1)props.children = children[0] else props.children = [...children] }Copy the code

Handwritten source

Const REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol. For? Symbol. For (' reac.Element '):0xeac7 /** * ReactElement * Factory function, creates a ReactElement, it is not a class, so it cannot be called with new, $$type = $$type = 'react 'Symbol. For ('react. Element ') * * */ const MyReactElement =function(type,key,ref,props){const element = { $$typeof:REACT_ELEMENT_TYPE, // react uses Symbol, type, key, ref, props} return element; } const RESERVED_PROPS={ key:true, ref:true } /** * * @param {*} type * @param {*} config * @param {... Any} children * @returns */ / create createElement function createElement (type,config,... Res){const props = {} let props,key = null,key if(config! ==null){ if(hasValidDescript(config,'ref')){ ref = config.ref } if(hasValidDescript(config,'key')){ key = config.key } Object. Keys (config).foreach (prop=>{if(! RESERVED_PROPS. HasOwnProperty (prop) {props[prop] = config[prop]}})} // Get children if(res.length>0){ if(res.length===1)props.children = res[0] else props.children = [...res] } return MyReactElement( type, key, ref, Function hasValidDescript(config,key){if(config &&) function hasValidDescript(config,key){if(config && Object.prototype.hasOwnProperty.call(config,key)){ return ! Object.getOwnPropertyDescriptor(config,key).get } return false } export default { createElement:CreateElement }Copy the code