coverPiccoverPic

React Hook:在组件挂载、更新、卸载时调用钩子

前言

众所周知,useEffect是一个会在 Function 组件中调用的副作用钩子,如下所示。

typestript
  1. import { useEffect } from 'react';
  2. useEffect(() => {
  3. // 组件挂载、dep数组改变时执行
  4. // 不写dep数组则每次组件更新都执行
  5. // dep数组为空则只在挂载时执行
  6. return () => {
  7. // 组件卸载时执行
  8. }
  9. }, dep)

此外,useLayoutEffect的机制也与useEffect极为相似,区别在于useEffect是在页面更新后(或者说 React 渲染的 commit 阶段后)后异步调用的,而useLayoutEffect在页面更新之前(或者说 React 渲染的 commit 阶段过程中)同步调用。

日常开发中,我们通常会针对业务需求使用到了类似于useUpdateEffectuseMountuseUnmount等等钩子函数,在更准确的时机触发回调。我们参考 react-useahook 之类的钩子函数库,探究这些常用钩子的原理,封装一套路由在组件挂载、更新、卸载时调用钩子。

useMountEffect & useMountLayoutEffect

当我们需要在页面更新时拉取数据时,可以使用一个useMountEffect或者useMountLayoutEffect,就像 Vue 的onMounted或者 Class 组件的componentDidMount。原理类似于 react use 的useMount

typescript
  1. import React, { useEffect, useLayoutEffect } from 'react';
  2. const mountEffect = (
  3. effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
  4. ) =>
  5. (effect: React.EffectCallback) => {
  6. effectHook(() => {
  7. return effect()
  8. }, [])
  9. }
  10. export const useMountEffect = mountEffect(useEffect)
  11. export const useMountLayoutEffect = mountEffect(useLayoutEffect)

useUnmountEffect & useUnmountLayoutEffect

类似的,当页面退出需要做些什么操作时,可以使用一个useUnmountEffect或者useUnmountLayoutEffect。原理类似于 react use 的useUnmount

typescript
  1. import React, { useEffect, useLayoutEffect, useRef } from 'react';
  2. const unmountEffect = (
  3. effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
  4. ) =>
  5. (effect: () => any) => {
  6. const callback = useRef(effect)
  7. callback.current = effect
  8. effectHook(() => {
  9. return callback.current
  10. }, [])
  11. }
  12. export const useUnmountEffect = unmountEffect(useEffect)
  13. export const useUnmountLayoutEffect = unmountEffect(useLayoutEffect)

useUpdateEffect & useUpdateLayoutEffect

假如有这样子的一个需求,在一个搜索框中用户输入关键字keyword后请求后端接口搜索列表,我们只希望请求数据的回调函数仅在keyword改变后触发,我们就需要useUpdateEffect或者useUpdateLayoutEffect。原理类似于 react use 的useUpdateEffect

typescript
  1. import React, { useEffect, useLayoutEffect, useRef } from 'react';
  2. const updateEffect = (
  3. effectHook: (effect: React.EffectCallback, deps: React.DependencyList) => void
  4. ) =>
  5. (
  6. effect: React.EffectCallback,
  7. deps: React.DependencyList,
  8. ) => {
  9. const isFirst = useRef(true);
  10. const callback = useRef(effect)
  11. callback.current = effect
  12. effectHook(() => {
  13. if (isFirst.current) {
  14. isFirst.current = false;
  15. return;
  16. }
  17. return callback.current();
  18. }, deps);
  19. }
  20. export const useUpdateEffect = updateEffect(useEffect)
  21. export const useUpdateLayoutEffect = updateEffect(useLayoutEffect)

结尾

本文参考了 react-use以及ahook 库,对useMount(Layout)EffectuseUpdate(Layout)EffectuseUnount(Layout)Effect钩子进行实现。

0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run