常用的React Hooks
Hooks
- 由于函数组件没有this,为了能够处理组件内部的状态以及副作用,提供了 Hooks 的方式
- 自定义Hooks可以便于组件逻辑的封装和复用,相比于HOC的使用更加方便和高效
- 常见的Hooks
- useState
- 存储组件内部状态,接收一个初始化的值后除非调用setState,否则state的值不会改变
- setState的参数可以为newState,也可以是一个函数,参数为oldState,返回值为newState
- useEffect
- 处理副作用的函数,接收两个参数,第一个参数为一个函数fn,第二个参数为监听变化的state数组
- 执行函数fn可以返回一个清理函数,在每次组件渲染完成之后都会调用该清理函数
- 依赖的state数组不传时,每次组件渲染都会执行函数fn
- 依赖的state数组传空数组时,只会在组件初次渲染时执行一次fn
- 当出现循环渲染时,需要考虑将循环的依赖替换为ref或者使用 useEffectEvent hook
- useLayoutEffect
- 与useEffect用法类似,但是内部的执行函数为同步执行,会阻塞浏览器渲染
- 它在SSR中无效,只能在客户端使用
- useCallback
- 用于缓存组件内的函数以提升性能,接收两个参数,第一个为要执行的函数,第二个为函数的依赖
- 与useEffect不同,该hook用于声明函数,需要在使用的时候手动调用执行
- useMemo
- 与useCallback类似,可以用来缓存基本的数据类型
- 若用来缓存函数,则跟useCallback效果一样
- useContext
- 用于读取和订阅组件中的context,通常与createContext搭配使用
- useReducer
- 根据Redux来的状态管理hook,接收两个参数,第一个为reducer,第二个为默认的state
- 返回一个数组,可解构为[state, dispatch],state为当前的状态值,dispatch用于触发状态更新
- 与 useContext 搭配可以实现跟 Redux 一样效果
- useRef
- 用于创建一个不触发渲染的值,值的更新和删除都不会触发组件渲染,且在组件每次渲染的context中都能获取到最新值
- useImperativeHandle
- 用于向父组件暴露出 ref,便于在父组件中直接调用子组件方法,需要搭配 forwardRef API使用(react19不需要)
- 接收三个参数,第一个为forwardRef中的ref,第二个为一个函数,返回的对象为父组件中ref获取到的对象,第三个参数为可选的依赖数组
- useState
useCallback
会返回一个被缓存的函数。
- 优化性能:如果一个函数作为子组件的props。每次渲染的时候,这个函数都会是新函数。那么props就会是新的。那么子组件永远都会重新渲染。就算子组件使用memo都无法避免。
- 避免不必要的计算:如果函数内部有昂贵的计算,可以避免重新计算。
- 如果函数作为某个hook的依赖,使用useCallback避免重复触发这个hook。如防止频繁触发useEffect。 如果useCallback没有依赖,将不生效。
useMemo
返回一个缓存的值
- 当一个函数计算成本比较高,避免重复计算(一般来说除非遍历上千对象,否则开销并不大)
- 当这个值是一个对象或数组,且是另一个子组件的props的时候,可以避免子组件每次都重新渲染。
- 当这个值是对象的时候,是另一个hook的依赖的时候,可以避免重复触发hook。
- 也可以记忆一个函数,和useCallback 类似。
useId
为了解决SSR中id生成的问题,之前我们可能使用uuid或随机数生成id,但是在ssr中,服务端和客户端生成的id不一样。
useLayoutEffect
可能影响性能,在浏览器重新绘制屏幕之前触发。可以进行dom操作,比如获取dom位置,防止用户看见闪烁。
useContext
结合CreateContext、Provide进行使用,用于向组件树深层传递数据。
useImperativeHandle
结合使用forwardRef,用于向父组件暴露ref。比如暴露方法,父组件可以调用子组件的方法。
useDeferredValue vs useTransition
useDeferredValue 可以延迟更新页面的内容,通过延迟更新state。 let v = useDeferredValue(state)
useTransition 可以在不阻塞UI的情况下更新React Hook。通过调用setState。 useTransition(() => setState)
useSyncExternalStore
可以订阅外部store,浏览器API
第一个参数是一个函数,函数内部做订阅逻辑,并return取消订阅
第二个参数是也是一个函数,return订阅的值。
let isOnLine = useSyncExternalStore(subscript, getSnapshot)