React Hook:在组件挂载、更新、卸载时调用钩子
前言
众所周知,useEffect是一个会在 Function 组件中调用的副作用钩子,如下所示。
typestript- import { useEffect } from 'react';
- useEffect(() => {
- // 组件挂载、dep数组改变时执行
- // 不写dep数组则每次组件更新都执行
- // dep数组为空则只在挂载时执行
- return () => {
- // 组件卸载时执行
- }
- }, dep)
此外,useLayoutEffect的机制也与useEffect极为相似,区别在于useEffect是在页面更新后(或者说 React 渲染的 commit 阶段后)后异步调用的,而useLayoutEffect在页面更新之前(或者说 React 渲染的 commit 阶段过程中)同步调用。
日常开发中,我们通常会针对业务需求使用到了类似于useUpdateEffect、useMount、useUnmount等等钩子函数,在更准确的时机触发回调。我们参考 react-use、ahook 之类的钩子函数库,探究这些常用钩子的原理,封装一套路由在组件挂载、更新、卸载时调用钩子。
useMountEffect & useMountLayoutEffect
当我们需要在页面更新时拉取数据时,可以使用一个useMountEffect或者useMountLayoutEffect,就像 Vue 的onMounted或者 Class 组件的componentDidMount。原理类似于 react use 的useMount。
typescript- import React, { useEffect, useLayoutEffect } from 'react';
- const mountEffect = (
- effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
- ) =>
- (effect: React.EffectCallback) => {
- effectHook(() => {
- return effect()
- }, [])
- }
- export const useMountEffect = mountEffect(useEffect)
- export const useMountLayoutEffect = mountEffect(useLayoutEffect)
useUnmountEffect & useUnmountLayoutEffect
类似的,当页面退出需要做些什么操作时,可以使用一个useUnmountEffect或者useUnmountLayoutEffect。原理类似于 react use 的useUnmount。
typescript- import React, { useEffect, useLayoutEffect, useRef } from 'react';
- const unmountEffect = (
- effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
- ) =>
- (effect: () => any) => {
- const callback = useRef(effect)
- callback.current = effect
- effectHook(() => {
- return callback.current
- }, [])
- }
- export const useUnmountEffect = unmountEffect(useEffect)
- export const useUnmountLayoutEffect = unmountEffect(useLayoutEffect)
useUpdateEffect & useUpdateLayoutEffect
假如有这样子的一个需求,在一个搜索框中用户输入关键字keyword后请求后端接口搜索列表,我们只希望请求数据的回调函数仅在keyword改变后触发,我们就需要useUpdateEffect或者useUpdateLayoutEffect。原理类似于 react use 的useUpdateEffect。
typescript- import React, { useEffect, useLayoutEffect, useRef } from 'react';
- const updateEffect = (
- effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
- ) =>
- (
- effect: React.EffectCallback,
- deps: React.DependencyList,
- ) => {
- const isFirst = useRef(true);
- const callback = useRef(effect)
- callback.current = effect
- effectHook(() => {
- if (isFirst.current) {
- isFirst.current = false;
- return;
- }
- return callback.current();
- }, deps);
- }
- export const useUpdateEffect = updateEffect(useEffect)
- export const useUpdateLayoutEffect = updateEffect(useLayoutEffect)
结尾
本文参考了 react-use以及ahook 库,对useMount(Layout)Effect、useUpdate(Layout)Effect、useUnount(Layout)Effect钩子进行实现。
