React 笔记:虚拟 DOM

2018/12/02 FrontEnd

了解 ProTypes 和 DefaultProps,state props 和 render,虚拟 DOM。

学习自慕课网视频:React 16.4 开发简书项目从零基础入门到实战

1.单向数据流

组件间,数据流是单向的,只能是父组件给子组件传值,子组件不能修改父组件的值,因为传过来的数据是 read only 的。

因为父组件的数据可能要给很多子组件,如果数据不是单向的,只要其中一个修改了数据,其他四个也会变化,这就很危险了,不容易定位问题。

如果的确需要改变父组件的数据,可以调用父组件的方法来进行修改。也就是说,把修改操作集中在父组件的方法里。

2.React 是一个视图层框架

只解决数据和页面渲染问题。怎么传递值,需要借助其他框架,比如 flux redux。

3.Chrome 插件 React Developer tools

帮助查看当前网页是否为 React 开发以及是否上线。

黑色表示不是 React 开发;红色表示 React 开发但没上线;蓝色表示 React 开发且上线。

安装了这个插件后,在控制台,可以方便的看到自定义组件的信息和数据。

4.ProTypes 和 DefaultProps

https://reactjs.org/docs/typechecking-with-proptypes.html

从父组件接收的值和默认值。

ProTypes : 属性接收的定义和校验,避免父组件传递非期待的数据类型。


//定义在组件底部

TodoItem.proTypes = {

 //属性:类型

 content: ProTypes.string,

 //后面的 isRequired 表示必须有,如果有默认属性,父组件不传过来也行

 deleteItem: ProTypes.func.isRequired,

 index: ProTypes.number

}



//默认属性

TodoItem.defaultProps = {

 content: 'hello world'

}

支持的数据类型

5.state props 和 render

一旦 state props 改变,render() 就会重新执行!因此数据改变时,页面会改变。

当父组件的 render() 执行时,子组件的 render() 也会被执行。

6.虚拟 DOM

以 TodoList 项目为例分析

自己实现的逻辑:

  1. state 数据

  2. JSX 模版

  3. 数据 + 模版 结合,生成真实的 DOM,显示

  4. state 数据改变

  5. 数据 + 模版 结合,生成真实的 DOM,替换

缺陷:生成整个 DOM、替换整个 DOM,性能不好,没有改变的区域也替换了。

改进:

  • 数据改变时,生成真实的 DOM,不直接替换原始的 DOM

  • 新 DOM 和原始 DOM 做对比,找差异

  • 找出 input 框发生了变化

  • 只用新 DOM 中的 input 元素,替换旧 DOM 的 input 元素

缺陷2:性能提升并不明显

虚拟 DOM:

虚拟 DOM 就是一个 JS 对象,用于描述真实的 DOM。

JS 中操作对象比创建、对比 DOM 性能要高多了。

  1. state 数据

  2. JSX 模版

  3. 数据 + 模版 结合,生成真实的 DOM,显示

  • hello world
  1. 生成虚拟 DOM (损耗了性能)
  • [‘div’, {id: abc}, [‘span’, {}, ‘hello world’]]

  • 虚拟 DOM 就是类似这样的一个 JS 对象,第一个属性表示标签;第二个表示 id 等附加信息;第三个表示显示的内容,可以为子组件,嵌套

  1. state 改变

  2. 数据 + 模版 生成新的虚拟 DOM(比创建真实的 DOM,极大的提升了性能)

  • [‘div’, {id: abc}, [‘span’, {}, ‘bye bye’]]
  1. 比较 4 中的虚拟 DOM 和 6 的新虚拟 DOM的区别,找到区别是 span 的内容(比在真实的 DOM 中对比区别性能高多了)

  2. 直接操作 DOM,改变 span 中的内容

在这里插入图片描述

先生成虚拟 DOM,然后才生成真实的 DOM

深入理解虚拟 DOM

JSX -> createElement -> 虚拟 DOM(JS 对象) -> 真实的 DOM


React.createElement('div', {}, '内容item');

JSX 存在的意义:避免我们直接调用 React.createElement() 方法的繁琐,提供的一种相对简单的写法。

虚拟 DOM 的优点:

  1. 性能提升

  2. 使得跨端应用得以实现

  • 从虚拟 DOM 到具体组件的实现过程,在不同端可以不同。

虚拟 DOM 中的 Diff 算法

在这里插入图片描述

多次 setState() 方法会被优化成只做一次调用,这就是为什么是异步操作而不是同步的原因。

在这里插入图片描述

同层比对算法:只要当前层级的节点不一致,所有孩子节点就会被重新创建。

使用一个稳定的 key 来标识某个 虚拟 dom 节点,不要使用 index,可能会在中间插入节点。

比如使用节点的内容。

React 中的 ref 引用

https://reactjs.org/docs/refs-and-the-dom.html

函数里获取 DOM 元素的方法:

1.通过 e.target 获取,调用 e.target.value 就能获取 dom 元素的值




//函数

handleInputChange(e){

 const value = e.target.value;

}

2.通过在组件里,定义 ref 属性的值


//JSX

<input

 //...

 ref={(input) => {this.input = input}}

/>



//函数

handleInputChange(){

 const value = this.input.value;

}

上面的 JSX 的 ref={(input) => {this.input = input}} 是什么意思呢?

第一个表示当前节点,名称可以随便取一个;第二个箭头函数里,把 this.input 指向了当前的 input DOM 元素。因此后面的函数里,我们就可以直接通过 this.input 来访问输入 DOM 了。

React 中的 ref 是帮助我们直接获取 DOM 元素的,一般情况下尽量不要直接使用它。

setState() 是一个异步函数,不会立即执行。要获取更新之后的状态,可以把函数放到 setState() 的第二个参数,该函数会执行结束之后的被回调。


handleBtnClick() {

 this.setState(

  (preState) => ({数据操作}),

  () => { render 执行结束之后的回调} 

 );

}

如果需要在页面刷新后获取页面的 DOM 节点,最好在 setState() 第二个参数里执行。

Search

    Table of Contents