参考React官方文档、https://www.jianshu.com/p/8dc...
JSX
JSX是一个 JavaScript 的语法扩展,在HTML模板中嵌入JavaScript语法。由于React认为组件渲染逻辑与UI视图存在内在耦合,而JSX 可以很好地描述UI应该呈现出它应有交互的本质形式,所以React建议使用JSX语法。JSX完全可以实现JavaScript原有的功能。
JSX本质是React.createElement的语法糖,如下图例子所示,JSX会被Babel编译为createElement函数调用
createElement()
ReactElement中createElement()是这样定义的`
function createElement(type,config,children)
调用createElement方法返回一个包含类型、属性、子节点的对象,这个对象称为React元素,也就是React vdom的节点
virtual dom是React性能优化的重要点,本质是JS对象,所有节点以键值对形式存在,节点也是JS对象,用嵌套形式表示dom的树形结构。
那么createElement方法具体做了什么事呢?
- 首先遍历config参数也就是节点的属性,保存在props对象中
- 把children参数封装成数组,保存在props对象中
- 根据type参数判断节点默认属性,将默认属性也保存在props对象
- 最后调用ReactElement方法并传入type、props,返回一个对象
ReactElement方法返回的对象长这样
- $$typeof属性用于检测节点是否为合法的React元素
- type属性即节点类型
- key用作节点的唯一标识
- ref用于获取真实的dom节点
- props包含了节点的默认属性和用户给它定义的属性以及子节点
- _owner标识该节点隶属于哪个组件
ReactDom.render
createElement创建的React元素是怎么渲染到页面的呢?ReactDom为用户提供了render方法渲染元素。
ReactDOM.render(element, container[, callback])
在提供的 container
里渲染一个 React 元素,并返回对该组件的引用(或者针对无状态组件返回 null
)。
如果 React 元素之前已经在 container
里渲染过,这将会对其执行更新操作,并仅会在必要时改变 DOM 以映射最新的 React 元素。
如果提供了可选的回调函数,该回调将在组件被渲染或更新之后被执行。
在实际项目中,所有组件作为子节点渲染到id为root的div容器
注意
-
ReactDOM.render()
会控制你传入容器节点里的内容。当首次调用时,容器节点里的所有 DOM 元素都会被替换,后续的调用则会使用 React 的 DOM 差分算法(DOM diffing algorithm)进行高效的更新。 -
ReactDOM.render()
不会修改容器节点(只会修改容器的子节点)。可以在不覆盖现有子节点的情况下,将组件插入已有的 DOM 节点中。 -
ReactDOM.render()
目前会返回对根组件ReactComponent
实例的引用。 但是,目前应该避免使用返回的引用,因为它是历史遗留下来的内容,而且在未来版本的 React 中,组件渲染在某些情况下可能会是异步的。 如果你真的需要获得对根组件ReactComponent
实例的引用,那么推荐为根元素添加 callback ref。 - 使用
ReactDOM.render()
对服务端渲染容器进行 hydrate 操作的方式已经被废弃,并且会在 React 17 被移除。作为替代,请使用hydrate()
。
为了避免每次计算dom节点差异时递归遍历dom树的操作,React团队给出了React Fiber算法以及fiber tree数据结构(基于单链表的树结构),而render方法就是实现React Fiber算法以及构建fiber tree的核心API。关于这部分的实现,请参考开头链接。
总结
总而言之,React渲染的过程实际上是由JSX创建React元素作为虚拟dom节点,调用render方法创建一棵虚拟dom树,然后映射到真实dom上由浏览器渲染出来。state和props改变时,会再次调用render生成一棵新的虚拟dom树,通过diff算法计算新旧两棵虚拟dom的差异,再异渲染到真实dom上
关于vdom改天再写一篇详细的总结
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。