React render
Virtual Dom转化为真实DOM
在 React 中,Virtual DOM(虚拟 DOM)是一个轻量级的 JavaScript 对象,它是真实 DOM 的一个表示。React 使用这个表示来优化 DOM 操作,提高性能。渲染 Virtual DOM 到真实 DOM 的过程通常是自动完成的,但理解这个过程可以帮助你更好地理解 React 的工作机制。
React 使用以下步骤将 Virtual DOM 渲染成真实 DOM:
组件更新:当一个 React 组件的状态(state)或属性(props)发生变化时,React 会更新该组件的 Virtual DOM。
生成 Virtual DOM:React 会调用组件的
render
方法,根据组件的最新状态和属性来生成一个新的 Virtual DOM 树。Diff 算法:React 使用 Diff 算法比较新的 Virtual DOM 树与上一次的 Virtual DOM 树的差异。这个过程称为重新协调(reconciliation)。
确定 DOM 更新:Diff 算法确定了在 Virtual DOM 树中哪些地方发生了变化。React 将这些变化(或“补丁”)转换为对真实 DOM 的操作指令。
真实 DOM 更新:React 批量执行这些 DOM 操作指令,更新真实的 DOM 树。React 会尽量最小化操作真实 DOM 的次数,因为这些操作通常是性能开销最大的。
引用更新:一旦真实 DOM 更新完毕,如果有必要,React 会更新组件的 refs。
这个过程在 React 应用程序中是自动发生的,作为开发者,你通常只需要关注组件的状态和属性,并编写对应的 render
方法。React 会负责将你的 Virtual DOM 高效地渲染至真实的 DOM。
如果你正在使用 React 的类组件,这个过程基本上是由 ReactDOM.render()
方法触发的,它将组件挂载到某个 DOM 元素上。对于函数组件,这个过程是由 React Hooks 如 useState
和 useEffect
来管理状态和副作用的。
在 React 16 及以后的版本中,这个过程得到了进一步的优化,引入了 Fiber 架构来更好地处理更新过程中的异步任务、分割可中断的工作等,以实现更高效的性能表现。
手动实现简单的render方法
封装一个对象迭代方法
for/in循环的弊端
for/in
循环在JavaScript中是用来遍历对象属性的一种方法,但它有几个弊端需要注意:
迭代继承的属性:
for/in
循环不仅遍历对象自身的属性,还会遍历其原型链上继承来的可枚举属性,这可能会引入意外的属性,特别是当使用第三方库或者框架时,可能会有很多继承的属性加入到对象上。仅限可枚举属性:
for/in
仅遍历对象的可枚举属性,这意味着使用Object.defineProperty()
方法定义的不可枚举属性将不会被遍历。忽略 Symbol 属性:
for/in
循环不会遍历使用 Symbol 作为键的属性,而这些属性可能代表了对象的重要部分。性能问题: 在某些情况下,尤其是对象属性数量庞大时,
for/in
的性能可能不如其他方法,比如Object.keys()
或Object.entries()
配合forEach()
或for/of
循环。
1 | // 一般来说内置的属性都是不可枚举的,自定义的属性都是可枚举的,(枚举:可以被for/in、Object.keys、JSON.stringify列举出来的属性),但可以通过Object.defineProperty()方法来定义属性的可枚举性 |
优化方案
可以使用Reflect.ownKeys()方法来获取对象的所有属性,包括Symbol属性
1 | /** |
封装render方法
render
方法会有两个参数:vNode(virtual Dom),container(挂载虚拟dom的节点),vNode数据结构大致为 {type: 'div', props: {id: 'app', children: []}}
,我们需要的是type和props
- 根据
type
创建真实dom - 遍历
props
,为当前dom添加对应属性
js通过dom[key] = value
和 setAttribute
都可以用来为DOM元素设置属性,但它们在一些方面有所不同:
属性类型:
dom[key] = value
是直接在DOM对象上设置一个属性或方法。这种方式设置的属性是JavaScript对象的属性。setAttribute
是设置DOM元素的HTML属性,它会影响到元素的HTML结构,并且最终的效果可以通过元素的outerHTML属性看到。
属性名的限制:
- 使用
dom[key] = value
时,key
对应的通常是元素的属性名,比如id
,title
或事件处理函数如onclick
等。这种方式不适合设置非标准属性,因为它可能不会正确反映在DOM上。 setAttribute
可以设置任何属性,包括自定义属性。如果设置的是非标准的属性,它会以自定义属性的形式出现在元素的标记上,例如data-*
属性。
- 使用
布尔属性:
- 使用
dom[key] = value
可以设置布尔属性,例如checked
,disabled
等。设置为true
或false
会正确地改变元素的状态。 setAttribute
则需要传递一个字符串,对于布尔属性来说,你通常会传递"true"
或"false"
,但实际上任何非空字符串都表示true
,包括字符串"false"
。为了删除一个布尔属性,你需要使用removeAttribute
。
- 使用
细微的行为差异:
dom[key] = value
设置的属性值可以直接通过JavaScript访问并且修改,这个变化是动态的,并且立即反映在对象上。setAttribute
更改的是HTML属性,这可能会导致某些属性有不同的表现,例如,将input
元素的value
属性通过setAttribute
设置,可能不会改变其当前显示的内容,因为value
属性设置的是默认值。
在大多数情况下,这两种方法可以互换使用,但是推荐使用 dom[key] = value
来设置标准的属性和事件处理函数,而使用 setAttribute
来设置自定义属性或者当你需要操作的属性在JavaScript对象中不是一个简单的属性时。
Render方法封装
1 | /** |
测试Render方法
1 | import { render } from './jsxHandler'; |