组件化思想
组件
组件是构建 React
应用的独立、可复用的代码块。它接收输入(称为 props
),并返回描述UI
的 React
元素。
函数组件 vs 类组件
- 函数组件:一个接受输入,并输出
JSX
的函数。 - 类组件:使用
class
定义,并继承React.Component
的类,必须包含一个render()
方法。
为什么函数组件成为主流
1、代码简洁:函数组件的语法更简单,没有this
绑定问题。
2、Hooks的引入:引入Hooks后,函数组件也能拥有状态和生命周期等能力。
受控组件 vs 非受控组件
- 受控组件:表单数据由
React
组件管理的组件。表单元素(input
、textarea
等)的值由state
控制,并通过onChange
事件来更新。 - 非受控组件:表单数据由DOM本身进行管理,可以使用
ref
从DOM节点中获取表单值。
状态和属性
state
(状态)
- 组件内部管理的数据,状态改变会触发组件的重新渲染。
- 如何更新:
- 类组件:使用
this.setState()
- 函数组件:使用
useState
Hook 返回更新函数 - 状态的更新是异步的,React会对同一个事件处理函数中的多个状态更新进行批处理
- 状态不可变,每次状态更新都会产生新的状态对象,直接修改状态不会重渲染
- 类组件:使用
props
(属性)
- 从组件外部传入的数据,类似函数的参数,只读,不能修改。
- 实现父组件向子组件通信(传递数据、回调函数等)
Hooks
1、useState
- 作用:在函数组件中添加内部状态
- 语法:
const [state,setState] = useState(初始值)
- 关键点:初始值可以是一个值,也可以是一个函数。调用
setState
会替换状态对象
2、useEffect
- 作用:在函数组件中执行副作用操作(数据获取,订阅,手动修改DOM等一些异步操作)
- 执行时机:默认情况下,在每次渲染后(包括首次渲染)都会执行。
- 依赖数组(第二个参数)的控制:
- 不提供依赖数组(
null
):每次渲染后都执行 - 依赖数组为空(
[]
):仅在组件挂载后执行一次(类似于componentDidMount
) - 依赖数组有值(
[dep1,dep2]
):在组件挂载后以及dep1
或dep2
发生改变时执行
- 不提供依赖数组(
- 清除效应:如果
useEffect
的回调函数返回一个函数,这个函数会在组件卸载前和执行下一个副作用之前被调用,可以用于清理(取消订阅、清除定时器等)
3、useContext
- 作用:接受一个Context对象(由
React.createContext()
创建)并返回该Context的当前值 - 实现与后代组件单向通信
4、useCallback
和useMemo
useCallback
:缓存函数本身,用于优化性能。- 在进行重新渲染时,
- 如果依赖项没有发生变化,返回的是相同的函数,从而跳过重新渲染。
- 当依赖项改变时,会更新函数,并重新渲染。
- 在进行重新渲染时,
useMemo
:缓存计算结果,用于优化性能- 避免每次重新渲染时都进行高开销的计算任务
- 仅在依赖项改变时重新计算。
在
JS
中每次运行function(){}
和()=>{}
都会生成新的函数对象。父组件中定义了一个回调函数,子组件中调用了这个函数。当父组件状态改变时,会重渲染父组件,父组件中子组件也会重渲染,其中父组件重新生成了一个新的函数对象(虽然它的功能不变,但函数的引用变了,是一个新的对象),传入子组件的回调函数变了,所以子组件也要重新生成。
如果使用
useCallback
缓存该回调函数,只要依赖数组中的元素不变,当父组件重渲染时,它会返回缓存好的函数对象,而不是生成一个新的函数对象,传入子组件的回调函数不变,子组件跳过重新渲染。
5、useRef
- 访问DOM元素
- 存储一个可变的值
- ref的current属性可以在组件的整个生命周期内持久存在,而且改变它不会触发组件重新渲染,可以用来存储定时器ID,上一次属性或状态等。
生命周期和Hooks
-
componentDidMount
:组件挂载后回调- 使用
useEffect
并提供一个空依赖数组[]
。
- 使用
-
componentDidUpdate
:组件状态更新时回调- 使用
useEffect
并不提供依赖数组或提供一个非空的依赖数组- 使用
useRef
来保存一个在组件生命周期内持久存在的值(isMounted
),它不会触发重渲染。 - 首次渲染时,
isMounted.current
为false
,将其设为true
但不执行更新逻辑。 - 后续渲染时,
isMounted.current
为true
,执行更新逻辑。
- 使用
- 使用
-
componentWillUnmount
:组件卸载之前回调- 在
useEffect
中返回一个清理函数并提供一个空依赖数组。
- 在
虚拟DOM
一个轻量级的Javascript
对象,是真实DOM的抽象,当组件状态改变时,React会先在虚拟DOM上进行比较计算,而不是直接操作DOM。
-
工作流程:
- 当状态改变时,会创建一个新的虚拟DOM树。
- 使用
Diffing
算法比较新旧两个虚拟DOM树,找出需要更新的最小部分 - 将计算出来的差异批量地应用到真实DOM上
-
减少对真实DOM树的操作,极大提高性能。开发者无需关心如何高效地更新
UI
,只需要关心数据状态。