React | React组件化开发(三)

简介: React | React组件化开发(三)

一、React性能优化SCU

React更新机制

  • React渲染流程:
  • render函数中返回一个jsx
  • jsx创建出来对应的React.createElement
  • 这些element最终会形成一个树结构(对应的话就是虚拟DOM)
  • 最后React会根据虚拟DOM去渲染出来一个真实DOM


React更新流程:

  • 当前props/state发生改变
  • render函数重新执行
  • 之后产生一棵新的DOM树(新的树结构)
  • 在新旧树结构中进行diff算法来对比差异
  • 之后计算出差异的点进行一系列的更新
  • 最后把需要更新的地方更新到真实的DOM中

React更新流程

  • React在props或state发生改变时,会调用React的render方法,会创建出一棵不同的树.
  • React需要基于这两棵不同的树之间的差异来判断如何有效的更新UI:


  • 如果一棵树参考另外一棵树进行完全比较更新,那么即使是最先进的算法(算法的复杂程度为O(n²)),其中n是树中元素的数量
  • 如果React中使用了该算法,那么展示1000个元素所需要执行的计算量将在亿的量级范围内.
  • 这个开销很大,那么React更新性能将会变得十分低效.


  • React对这个算法进行了优化,将其优化成了O(n),如何优化的呢?
  • 同层节点之间相互比较,不会跨节点比较
  • 不同类型的节点,产生不同的树结构
  • 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定.

keys的优化

  • 我们在之前遍历列表时,总是会提示一个警告,让我们加入一个key属性:
  • 方式一:在最后位置插入数据
  • 这种情况有没有key其实意义并不是很大


  • 方式二:在前面插入数据
  • 这种情况在没有key的情况下,所有的li都会进行修改


  • 当子元素(li)拥有key时,React使用key来匹配原有树上的子元素以及最新树上的子元素
  • 在这种场景下,key为111和222的元素仅仅进行了位移,不需要进行任何的修改
  • 将key为333的元素插入到最前面的位置即可


  • key的注意事项
  • key应该是唯一的
  • key不要使用随机数(随机数会在下一次render时,重新生成一个新数)
  • 使用index作为key,对性能是没有优化的

render函数被调用

  • 嵌套案例:
  • 在App中,我们增加了一个计数器的代码
  • 当点击+1时,hUI重新调用App的render函数
  • 而当App的render函数被调用时,所有的子组件的render函数都会被重新调用

5b7c7ce05e184faf8ebe843d77e6ec73.png

那么,在之后的开发中,我们只是修改了App中的数据,是,所有的组件都需要重新render,进行diff算法,性能肯定非常低:

  • 事实上,很多的组件是没有必要去重新render的
  • 它们调用render应该有一个前提,就是依赖的数据(state,porps)发生改变,再去调用render方法;


  • 那么怎么来控制render方法是否被调用?
  • 通过shouldComponentUpdate方法即可

shouldComponentUpdate

  • React提供了一个生命周期方法 shouldComponentUpdate(简称:SCU)这个方法接收参数,并且需要有返回值:


  • 该方法有两个参数:
  • nextProps => 修改之后,新的props属性
  • nextState => 修改之后,新的state属性


  • 该方法返回值是一个boolean类型:
  • 返回值为true时,就需要调用render方法
  • false则不需要调用
  • 默认返回是true,也就是只要state/props发生改变,就会调用


  • 比如我们在App中增加一个message属性:
  • jsx中并没有依赖message,那么她的改变不应该引起重新渲染
  • 但是因为render监听到了state中的改变,就会重新render,所以最后render方法还是被调用了.

778916e739f94d83bc3f736d06280bd8.png

PureComponent

  • 如果所有的类都需要手动去实现 shouldComponentUpdate,那么会给开发带来很多的重复工作量
  • 我们设想一下shouldComponentUpdate中的各种判断目的是什么?
  • props/state中的数据是否发生了改变,来决定shouldComponentUpdate返回true/false


  • 事实上React已经考虑到了这一点,所以React已经默认帮我们实现好了,那么如何实现的?
  • 将class继承自PureComponent

809c5ce218c24f769367ae49ccc928f4.png

shallowEqual方法

这个方法中,调用 !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState), 这个shallowEqual就是 进行浅层比较:

74948de2606c41a8a161e79cd2cc2a41.png

高阶组件memo

  • 目前我们是针对类组件可以使用PureComponent,那么函数式组件呢?
  • 事实上函数式组件我们在props没有改变时,也是不希望其重新渲染其DOM树结构的


  • 我们需要使用一个高阶组件memo:
  • 通过memo函数进行一层包裹

4dfc07da182e4897a2f6764ef0ac7d3c.png

不可变数据的力量

f951d253655d4764a2e85628715e9fb9.png

570511970b1548f39ea5a1b8a360faa9.png

二、获取DOM方式refs

如何使用ref

  • 在React的开发模式中,通常情况下不需要,也不建议直接操作DOM原生,但是某些特殊的情况,确实需要获取到DOM进行某些操作:
  • 管理焦点,文本选择或媒体播放
  • 触发强制动画
  • 集成第三方 DOM 库
  • 我们可以通过refs获取DOM


如何创建refs来获取对应的DOM呢?目前有三种方式:

  • 一:传入字符串
  • 使用时通过 this.refs.传入的字符串格式获取对应的元素


  • 二:传入一个对象
  • 对象是通过 React.createRef() 方式创建出来的
  • 使用时获取到创建的对象其中有一个current属性就是对应的元素;


三:传入一个函数

  • 该函数会在DOM被挂载时进行回调,这个函数会传入一个 元素对象,我们可以自己保存
  • 使用时,直接拿到之前保存的元素对象即可

e26a3d0cc3474305acaf02521f45a395.png

ref的类型

  • ref 的值根据节点的类型而有所不同:
  • 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性


  • 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性


  • 你不能在函数组件上使用 ref 属性,因为他们没有实例


  • 函数式组件是没有实例的,所以无法通过ref获取他们的实例
  • 但是某些时候,我们可能想要获取函数式组件中的某个DOM元素
  • 这个时候我们可以通过 React.forwardRef.

三、受控和非受控组件

认识受控组件

  • 在React中,HTML表单的处理方式和普通的DOM元素不太一样:表单元素通常会保存在一些内部的state


  • 比如下面的HTML表单元素:
  • 这个处理方式是DOM默认处理HTML表单的行为,在用户点击提交时会提交到某个服务器中,并且刷新页面
  • 在React中,并没有禁止这个行为,它依然是有效的
  • 但是通常情况下会使用JavaScript函数来方便的处理表单提交,同时还可以访问用户填写的表单数据
  • 实现这种效果的标准方式是使用“受控组件"

受控组件的基本演练

  • HTML 中,表单元素(如 input 和 select)之类的表单元素通常自己维护 state并根据用户输入进行更新


  • 而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新


  • 将两者结合起来,使React的state成为“唯一数据源”
  • 渲染表单的 React 组件还控制着用户输入过程中表单发生的操作
  • 被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”


  • 由于在表单元素上设置了 value 属性,因此显示的值将始终为 this.state.value,这使得 React 的 state 成为唯一数据源


  • 由于 handleUsernameChange 在每次按键时都会执行并更新 React 的 state,因此显示的值将随着用户输入而更新

Element

Value property

Change callback

New value in the callback

Input type="text"

value="string"

onChange

e.target.value

Input type="checkbox"

checked={boolean}

onChange

e.target.checked

Input type="radio"

checked={boolean}

onChange

e.target.checked

textarea

value="string"

onChange

e.target.value

select

value="option value"

onChange

e.target.value

受控组件的其他演练

  • textarea标签
  • texteare标签和input比较相似


  • select标签
  • select标签的使用也非常简单,只是它不需要通过selected属性来控制哪一个被选中.它可以匹配state的value来选中


  • 处理多个输入
  • 多处理方式可以像单处理方式那样进行操作,但是需要多个监听方法:
  • 这里我们可以使用ES6的一个语法:计算属性名(Computed property names): []

非受控组件(不推荐使用)

  • React推荐大多数情况下使用 受控组件 来处理表单数据:
  • 一个受控组件中,表单数据是由 React 组件来管理的
  • 另一种替代方案是使用非受控组件,这时表单数据将交由 DOM 节点来处理


  • 如果要使用非受控组件中的数据,那么我们需要使用 ref 来从DOM节点中获取表单数据


  • 在非受控组件中通常使用defaultValue来设置默认值


  • 同样,input checkbox 和 input radio 支持defaultChecked, select和textarea支持defaultValue
相关文章
|
1月前
|
设计模式 存储 前端开发
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
React开发设计模式及原则概念问题之自定义Hooks的作用是什么,自定义Hooks设计时要遵循什么原则呢
|
2月前
|
前端开发 JavaScript 安全
TypeScript在React Hooks中的应用:提升React开发的类型安全与可维护性
【7月更文挑战第17天】TypeScript在React Hooks中的应用极大地提升了React应用的类型安全性和可维护性。通过为状态、依赖项和自定义Hooks指定明确的类型,开发者可以编写更加健壮、易于理解和维护的代码。随着React和TypeScript的不断发展,结合两者的优势将成为构建现代Web应用的标准做法。
|
2天前
|
XML 移动开发 前端开发
使用duxapp开发 React Native App 事半功倍
对于Taro的壳子,或者原生React Native,都会存在 `android` `ios`这两个文件夹,而在duxapp中,这些文件夹的内容是自动生成的,那么对于需要在这些文件夹中修改的配置内容,例如包名、版本号、新架构开关等,都通过配置文件的方式配置了,而不需要需修改具体的文件
|
5天前
|
资源调度 JavaScript 前端开发
使用vite+react+ts+Ant Design开发后台管理项目(二)
使用vite+react+ts+Ant Design开发后台管理项目(二)
|
27天前
|
存储 前端开发 JavaScript
react 组件化
【9月更文挑战第2天】react 组件化
29 5
|
1月前
|
JavaScript 前端开发 安全
[译] 使用 TypeScript 开发 React Hooks
[译] 使用 TypeScript 开发 React Hooks
|
1月前
|
前端开发 JavaScript
React Server Component 使用问题之添加jsx的组件化能力,如何操作
React Server Component 使用问题之添加jsx的组件化能力,如何操作
|
1月前
|
移动开发 前端开发 JavaScript
"跨界大战!React Native、Weex、Flutter:三大混合开发王者正面交锋,揭秘谁才是你移动应用开发的终极利器?"
【8月更文挑战第12天】随着移动应用开发的需求日益增长,高效构建跨平台应用成为关键。React Native、Weex与Flutter作为主流混合开发框架各具特色。React Native依托Facebook的强大支持,以接近原生的性能和丰富的组件库著称;Weex由阿里巴巴开发,性能优越尤其在大数据处理上表现突出;Flutter则凭借Google的支持及独特的Dart语言和Skia渲染引擎,提供出色的定制能力和开发效率。选择时需考量项目特性、团队技能及生态系统的成熟度。希望本文对比能助你做出最佳决策。
118 1
|
1月前
|
前端开发
React——开发调式工具安装【五】
React——开发调式工具安装【五】
26 0
React——开发调式工具安装【五】
|
28天前
|
开发者 自然语言处理 存储
语言不再是壁垒:掌握 JSF 国际化技巧,轻松构建多语言支持的 Web 应用
【8月更文挑战第31天】JavaServer Faces (JSF) 框架提供了强大的国际化 (I18N) 和本地化 (L10N) 支持,使开发者能轻松添加多语言功能。本文通过具体案例展示如何在 JSF 应用中实现多语言支持,包括创建项目、配置语言资源文件 (`messages_xx.properties`)、设置 `web.xml`、编写 Managed Bean (`LanguageBean`) 处理语言选择,以及使用 Facelets 页面 (`index.xhtml`) 显示多语言消息。通过这些步骤,你将学会如何配置 JSF 环境、编写语言资源文件,并实现动态语言切换。
28 0