React是一个用于构建用户界面的Javascript库。它具有声明式、组件化和跨平台的优点。
本文将围绕着以下内容展开:
- 一些基本概念
- 什么业务场景下需要使用React
- 什么是组件,组件的组成部分
- 组件渲染过程
- 使用useEffect与外部交互
一些基本概念
命令式编程(Imperative):详细的命令程序(How)去处理一件事情以达到最终目的。
声明式编程(Declarative):只告诉程序需要达成的目的(What),具体的过程由程序自己摸索处理。
纯函数(Pure function):输入同样的数据,在任何上下文环境中得到的结果是一致的。可以理解为数学概念中的公式
文档对象模型(DOM):DOM是W3C定义操作标记语言(html/xml)的规范,DOM可以被任何的编程语言实现,浏览器实现了javascript版本的DOM,这是使得浏览器能够通过javascript操作网页内容
虚拟DOM(Virtual DOM):是React模拟的真实DOM的javascript对象。
什么业务场景下需要使用React
浏览器显示html内容的大致过程是:首先把html标签解析为DOM树,然后绘制DOM树内容到屏幕上。通过浏览器提供的Web接口,可以通过javascript动态的更新DOM节点的内容,DOM的更新会触发浏览器重新的绘制最新的内容到屏幕。
html → DOM树 → 绘制 → 更新DOM → 重新绘制。
而React则不同,它是通过浏览器提供的Web接口来更新DOM。React使用跟html类似标记语言jsx来创建元素,项目发布的时候,会把jsx编译为具体的javascript代码(React.createElement)。
React项目显示网页内容的大致过程如下:首先React.createElement创建虚拟DOM,然后比较虚拟DOM和真实DOM之间的差异,把有差异的部门提交给浏览器绘制。
React创建虚拟DOM → 比较虚拟DOM和真实DOM差异 → 同步差异到真实DOM → 浏览器绘制
与直接通过html绘制网页内容不同,React提供了虚拟DOM这个中间层,使得React有能力做到更加精准的按需更新真实DOM,从而提升网页性能(浏览器绘制是一个高消耗操作)。
通过上面的介绍可以看出,React对于业务交互状态复杂的项目更有优势,因为它能做到按需更新,减少浏览器绘制的次数,从而提升网页性能。相反的,对于业务交互状态简单的项目,使用React来构建有点杀鸡用牛刀。
React的组件可以允许你把UI拆分为功能独立的代码片段,可以让开发者专注于更小粒度的代码逻辑。通过组合多个组件来创建复杂的UI。
总结
以下场景可以考虑使用React来构建
- 交互状态复杂
- UI复杂
什么是组件,组件的组成部分和运行过程
组件是功能独立的代码片段,是特殊的函数,它的特殊之处在于函数的返回值必须是通过React.createElement来生成。以函数的视角来理解组件会清晰很多。定义组件就是定义函数,使用组件就是函数调用。
定义组件
const Logo = () => {
return <h1>LOGO</h1>; //jsx被编译后为React.createElement("h1", null, "LOGO");
};
const Header = () => {
return (
<>
<Logo />
</>
);
};
以上代码定义了Logo和Header 两个组件,其中Header使用了Logo。
如果已函数的视角来理解是这样的:定义了Logo和Header两个函数,在Header中调用了Logo这个函数。
组件的组成部分
组件是一个特殊的函数,函数有的特性,组件也有,它特殊之处在于:
- 函数的参数必须是immutable,函数参数就是组件的props
- 函数必须有返回值,并且返回值都使用react.createElement接口创建
只有参数和返回值的组件,称之为Pure组件。
组件除了需要外部传入的props数据外,有些场景也需要内部可改变的私有数据,在React中称为state,state类型的数据具有以下特点:
- state数据是mutable
- 只能在组件内部修改,使用set函数(useState/useReducer)更新
- state更新会触发react的重新渲染的请求
- state能在同一个组件实例多次渲染共享数据
- state数据独立于组件之外,由React维护。组件的渲染就是函数的调用,属性的更新会触发组件的重新渲染,多次渲染之后state的值依旧能保持,那么state只能存在于组件之外,否则组件每次重新渲染都会导致state被重置
总结
组件由以下部分组成:
- props,不可变数据,由使用方传入
- state,内部可变数据,由组件内部更新
- 返回值,每个组件的返回值都是用react.createElement创建
组件的渲染过程
所有组件在被浏览器绘制之前,都必须先由React渲染,然后在由React提交给浏览器绘制。理解这个渲染过程有助于了解组件的代码是如何被执行的。
组件从使用到最终被浏览器绘制大约会经历以下3个步骤:
- 触发渲染请求,React接受到渲染请求后,会将其加入渲染队列
- 执行渲染,执行相关的组件函数内的代码,执行函数的过程就是React渲染,渲染结束后React会生成一个结果(包含需要更新的DOM信息)进入下一步
- 提交结果,把最新的UI信息同步给浏览器绘制
- 执行useEffect设置的函数(可选),本节讨论会忽略这个过程
有以下两个原因会触发渲染请求:
- 初始化,React项目在第一次启动的时候,会创建初始化渲染的请求
- 重新渲染,通常state、props、Context的变化都会触发渲染请求
初始化渲染的过程
- 触发渲染。在项目入口中调用
createRoot(rootEl).render(<Component />) - 执行渲染。执行相关的组件函数生成虚拟DOM节点
- 提交结果。使用Web API的appendChild(),把全部的虚拟DOM交给浏览器绘制
重新渲染的过程
- 触发渲染。一旦初始化渲染完成之后,可以通过更新state触发重新渲染,React会把请求加入的渲染队列。
- 执行渲染。调用函数,根据组件相关信息生成最新的组件快照,用最新组建快照和上一次的组件快照比较,如果没有任何区别,则什么也不做,否则进入到下一步。
- 提交结果。React会计算出一个最小更新结果,交给浏览器绘制。
使用useEffect与外部交互
外部指:任何不被react管理的代码部分都叫做外部。
useEffect让组件有了与外部交互的能力,使用useEffect需要传递2个参数:
- setup函数,这个函数用于与外部系统交互,并返回一个cleanup函数,用于组件被重新渲染前执行清理操作。
- 依赖列表,初始化渲染完成之后,会执行setup函数(在开发环境中的StrictMode会被调用两次),重新渲染组件会根据依赖列表是否发生变化来决定是否执行setup函数。如果不设置依赖列表,setup函数会在每次渲染完成之后都会执行。如果设置一个空数组
[]则setup只会在初始化渲染的时候被调用