1、useRef hook
使用场景:在 React 中进行 DOM 操作时,用来获取 DOM
作用:返回一个带有 current 属性的可变对象,通过该对象就可以进行 DOM 操作了。
解释:
- 参数:在获取 DOM 时,一般都设置为 null
- 返回值:包含 current 属性的对象。
- 注意:只要在 React 中进行 DOM 操作,都可以通过 useRef Hook 来获取 DOM(比如,获取 DOM 的宽高等)。
- 注意:useRef不仅仅可以用于操作DOM,还可以操作组件
2、useContext hooks
2.1 context基础
使用场景:跨组件共享数据。
Context 作用:实现跨组件传递数据,而不必在每个级别手动传递 props,简化组件之间的数据传递过程
Context 对象包含了两个组件
- <Context.Provider value>:通过 value 属性提供数据。
- <Context.Consumer>:通过 render-props 模式,在 JSX 中获取 Context 中提供的数据。
注意:
- 如果提供了 Provider 组件,Consumer 获取到的是 Provider 中 value 属性的值。
- 如果没有提供 Provider 组件,Consumer 获取到的是 createContext(defaultValue) 的 defaultValue 值。
2.2 useContext使用
作用:在函数组件中,获取 Context 中的值。要配合 Context 一起使用。
useContext Hook 与 <Context.Consumer> 的区别:获取数据的位置不同,
- <Context.Consumer>:在 JSX 中获取 Context 共享的数据。
- useContext:在 JS 代码中获取 Context 的数据。
解释:
- useContext 的参数:Context 对象,即:通过 createContext 函数创建的对象。
- useContext 的返回值:Context 中提供的 value 数据。
3、React.memo高阶组件
3.1 介绍
React.memo 高阶组件的使用场景说明:
React 组件更新机制:只要父组件状态更新,子组件就会无条件的一起更新。
- 子组件 props 变化时更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)-> 渲染(变化后的内容)【 DOM 操作】。
- 子组件 props 无变化更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)【无 DOM 操作】。
注意:此处更新指的是组件代码执行、JSX 进行 Diff 操作(纯 JS 的操作,速度非常快,不会对性能产生太多影响)。
- 如果组件 props 改变了,那么,该组件就必须要更新,才能接收到最新的 props。
- 但是,如果组件 props 没有改变时,组件也要进行一次更新。实际上,这一次更新是没有必要的。
如果要避免组件 props 没有变化而进行的不必要更新(Diff),这种情况下,就要使用 React.memo 高阶组件。
注:对于 class 组件来说,可以使用 PureComponent 或 shouldComponentUpdate 钩子函数来实现
。
3.2 语法
使用场景:当你想要避免函数组件 props 没有变化而产生的不必要更新时,就要用到 React.memo 了。
作用:记忆组件上一次的渲染结果,在 props 没有变化时复用该结果,避免函数组件不必要的更新。
解释:
- React.memo 是一个高阶组件,用来记忆(memorize)组件。
- 参数(Child):需要被记忆的组件,或者说是需要避免不必要更新的组件。
- 返回值(MemoChild):React 记住的 Child 组件。
原理:通过对比检查更新前后 props 是否相同,来决定是否复用上一次的渲染结果,
- 如果相同,复用上一次的渲染结果;
- 如果不同,重新渲染组件。
并不是所有的组件都适合使用memo,比如child2组件,每次都需要重新渲染,使用memo反而会使性能变得更低,逻辑也变得更复杂
3.3 浅层对比
默认情况下,React.memo 只会对更新前后的 props 进行浅对比(shallow compare)与 PureComponent 相同。
也就是说,对于对象类型的 prop 来说,只会比较引用
- 如果更新前后的引用相同,复用上一次的渲染结果(不会重新渲染该组件)。
- 如果更新前后的引用不同,重新渲染该组件。
如果你要手动控制比较过程,可以使用 React.memo 的第二个参数:
解释:
- 第二个参数:用来比较更新前后 props 的函数。
- 返回值:如果返回 true,表示记住(不重新渲染)该组件;如果返回 false,表示重新渲染该组件。
4、useCallback hook
4.1 使用场景
在使用 React.memo 时,对于对象类型的 props,只会比较引用(浅对比)。
但是,因为组件每次更新都会创建新的 props 值,比如,新的对象、事件处理程序等(函数组件的特性)。
这就导致:React.memo 在处理对象类型的 props 时,会失效(每次的 props 都是新对象)。
但是,我们还是想让 React.memo 在处理对象类型的 props 时,也有效。
为了让 React.memo 处理对象类型的 props 有效,只要在组件更新期间保持对象类型引用相等,就可以了。
这时候,就要用到以下两个 Hooks:
-
useCallback
Hook:记住函数的引用,在组件每次更新时返回相同引用的函数。 -
useMemo
Hook:记住任意数据(数值、对象、函数等),在组件每次更新时返回相同引用的数据【功能之一】
4.2 基本使用
使用场景:在使用 React.memo 时,为了组件每次更新时都能获取到相同引用的函数,就要用到 useCallback Hook
注意:需要配合 React.memo 高阶函数一起使用。
作用:记忆传入的回调函数,这个被记住的回调函数会一直生效,直到依赖项发生改变
解释:
- 第一个参数:必选,需要被记忆的回调函数。
- 第二个参数:必选,依赖项数组,用于指定回调函数中依赖(用到)的数据(类似于 useEffect 的第二个参数)。
- 即使没有依赖,也得传入空数组([]),此时,useCallback 记住的回调函数就会一直生效。
- 返回值:useCallback 记住的回调函数。
- useCallback 记住的回调函数会一直生效(或者说会一直返回同一个回调函数),直到依赖项发生改变。
useCallback需要配置React.memo使用才有意义,不然反而性能更低,因为useCallback来包裹函数也是需要开销的
5、useMemo hook
使用场景:类似于 useCallback,可以在组件更新期间保持任意数据引用相等,一般用来处理对象类型的数据
对比:useCallback 只能记忆函数,而 useMemo 可以记忆任意数据。
作用:记忆任意数据,这个被记住的数据会一直生效,直到依赖项发生改变1。
语法
- 第一个参数:必选,回调函数。注意:该回调函数会被调用,并通过返回值指定需要被记住的数据。
- 第二个参数:必选,依赖项数组,用于指定回调函数中依赖(用到)的数据。同样,没有依赖项时,传入空数组([])。
- 返回值:useMemo 记住的数据
- useMemo 记住的数据会一直生效(或者说会一直返回同一个数据),直到依赖项发生改变。
如何选择使用哪一个?
- 如果处理的是函数,推荐使用 useCallback Hook。
- 如果处理的是其他数据(比如,对象),推荐使用 useMemo Hook。
5.1 模拟useCallback的用法
useCallback(fn, deps)
相当于 useMemo(() => fn, deps)
。
5.2 避免昂贵的计算(计算属性)