React元素只读性
Object.freeze方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。Object.freeze() | MDN
1 2 3 4 let element = { name : '邓立' }Object .freeze(element)element.sex = '男' console .log(element);
Object.freeze()原理1 2 3 4 5 6 7 8 9 10 11 12 13 Object .defineProperties(Object , 'freeze' , { value: function (obj ) { var i; for (i in object) { if (Object .hasOwnProperty(i)) { Object .defineProperty(obj, i, { writable: false }) } } Object .seal(obj) } })
使用相关函数解释
Object.defineProperties 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。Object.defineProperties | MDN
hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。hasOwnProperty() | MDN
Object.seal() 方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。Object.seal() | MDN JSX转换
React 17 之前会使用 React.createElement() 进行转换,React17之则引用了新的jsx处理转换方法
源代码1 2 3 4 import React from 'react' ;function App ( ) { return <p > Hello World</p > ; }
React16 转换1 2 3 4 5 import React from 'react' ;function App ( ) { return React.createElement('p' , null , 'Hello world' ); }
React17 转换1 2 3 4 5 import {jsx as _jsx} from 'react/jsx-runtime' ;function App ( ) { return _jsx('p' , { children : 'Hello world' }); }
想使用之前的方式转换需要在package.json里设置1 2 3 4 5 6 "scripts": { "start": "set DISABLE_NEW_JSX_TRANSFORM=true&&react-scripts start", "build": "set DISABLE_NEW_JSX_TRANSFORM=true&&react-scripts build", "test": "set DISABLE_NEW_JSX_TRANSFORM=true&&react-scripts test", "eject": "set DISABLE_NEW_JSX_TRANSFORM=true&&react-scripts eject" },
React源码解析 页面结构 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import React from './react' import ReactDOM from 'react-dom' function ReactTest (props ) { return (<div className ='title' style ={{ background: 'pink ', color: 'purple ' }}> <span > {props.name}</span > </div > )} ReactDOM.render( <ReactTest name='前端了了liaoliao' />, document .getElementById('root' ) );
效果展示 React之createElement源码分析
React.createElement('p', null, 'Hello world')通过传递的数据,转成树形数据(即虚拟DOM)的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function createElement (type, config, children ) { let props = { ...config } if (arguments .length > 3 ) { children = Array .prototype.slice.call(arguments , 2 ) } props.children = children return { type, props } } const React = { createElement }export default React
ReactDOM之render源码分析
想要了解render源码,必须清楚render的目的是把虚拟dom转换为真实DOM的过程。
原生组件渲染处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 function render (vdom, container ) { const dom = createDOM(vdom) container.appendChild(dom) } function createDOM (vdom ) { if (typeof vdom === 'number' || typeof vdom === 'string' ) { return document .createTextNode(vdom) } let { type, props } = vdom let dom = null if (typeof type === 'function' ) { return momentFunctionComponent(vdom) } else { if (type) { dom = document .createElement(type) } } updateProps(dom, props) if (typeof props.children === 'string' || typeof props.children === 'number' ) { dom.textContent = props.children } else if (typeof props.children === 'object' && props.children.type) { render(props.children, dom) } else if (Array .isArray(props.children)) { reconcileChildren(props.children, dom) } else { console .log('baocuo' ); dom.textContent = props.children ? props.children.toString() : '' } return dom } function momentFunctionComponent (vdom ) { let { type : FunctionComponent, props } = vdom let renderVdom = FunctionComponent(props) return createDOM(renderVdom) } function reconcileChildren (childrenVdom, parentDOM ) { for (let i = 0 ; i < childrenVdom.length; i++) { let childVdom = childrenVdom[i] render(childVdom, parentDOM) } } function updateProps (dom, newProps ) { for (let key in newProps) { if (key === 'children' ) continue ; if (key === 'style' ) { let styleObj = newProps.style for (let attr in styleObj) { dom.style[attr] = styleObj[attr] } } else { dom[key] = newProps[key] } } } const ReactDOM = { render }export default ReactDOM
React 类组件渲染 首先我们要创建一个React class需要继承的类声明
1 2 3 4 5 6 7 8 9 10 import { createDOM } from './react-dom' class Component { static isReactComponent = true constructor (props) { this .props = props this .state = {} } } export default Component
添加处理此类的方法
在判断是函数后,根据创建类时的添加的 isReactComponent 参数判断 1 2 3 4 5 6 7 if (typeof type === 'function' ) { if (type.isReactComponent) { return mountClassComponent(vdom) } else { return momentFunctionComponent(vdom) } }
处理类的方法 mountClassComponent 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function mountClassComponent (vdom ) { let { type, props } = vdom let classInstance = new type(props) let renderVdom = classInstance.render() let dom = createDOM(renderVdom) classInstance.dom = dom return dom }
页面测试 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class ReactComponent extends React .Component { render() { return ( <div> <p>测试React类是否展示</p> <p>{this .props.name}</p> </div> ) } } ReactDOM.render( <ReactComponent name='前端了了liaoliao' />, document .getElementById('root' ) );
页面展示
下期预告:合成时间及状态更新的源码解析 项目地址github