资讯专栏INFORMATION COLUMN

如何用ahooks控制时机的hook?

3403771864 / 442人阅读

  本篇主要和大家沟通关于ahooks ,我们可以理解为加深对 React hooks 的了解。

  我们先说下关于抽象自定义 hooks。构建属于自己的 React hooks 工具库。

  其实我们应该培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。

  注:本系列对 ahooks 的源码解析是基于v3.3.13。

  现在就进入主题用ahooks 来封装 React要注意的“时机”?

  Function Component VS Class Component

  很多时候代码要讲究先后顺序,要掌握周期,且需知道在不同的阶段执行不同操作的代码,比如需要挂载完成之后才去获取 dom 的值,否则可能会获取不到相应的值。

  Class Component

  使用过 React 的 Class Component 的同学,就会知道其组件生命周期会分成三个状态:

  Mounting(挂载):已插入真实 DOM

  Updating(更新):正在被重新渲染

  Unmounting(卸载):已移出真实 DOM

  简单版如下所示:

1.png

  其中每个状态中还会按顺序调用不同的方法,直接看下图:

2.png

  先要详细了解,就去官网详看。可以看到,会有非常多的生命周期方法,而且在不同的版本,生命周期方法还不同。

  Function Component

  没有生命周期的概念—Function Component ,它是更彻底的状态驱动,它只有一个状态,React 负责将状态渲染到视图中。

  对于 Function Component 来说由状态到页面渲染只有三步:

  输入状态(prop、state)

  执行组件的逻辑,并在useEffect/useLayoutEffect中订阅副作用

  输出UI(Dom节点)

  重点是第二步,React 通过 useEffect/useLayoutEffect 订阅副作用。Class Component 中的生命周期都可以通过 useEffect/useLayoutEffect 来实现。它们两个的功能非常相似,我们这里看下 useEffect。

  使用 useEffect 相当于告诉 React 组件需要在渲染后执行某些操作,React 将在执行 DOM 更新之后调用它。React 保证了每次运行 useEffect 的时候,DOM 已经更新完毕。这就实现了 Class Component 中的 Mounting(挂载阶段)。

  当状态发生变化的时候,它能够执行对应的逻辑、更行状态并将结果渲染到视图中,这就完成了 Class Component 中的 Updating(更新阶段)。

  最后通过在 useEffect 中返回一个函数,它便可以清理副作用。它的规则是:

  首次渲染不会进行清理,会在下一次渲染,清除上一次的副作用。

  卸载阶段也会执行清除操作。

  通过返回一个函数,我们就能实现 Class Component 中的 Unmounting(卸载阶段)。

  基于 useEffect/useLayoutEffect,ahooks 做了一些封装,能够让你更加清晰的知道你的代码执行时机。

  LifeCycle - 生命周期

  useMount

  只在组件初始化时执行的 Hook。 useEffect 依赖假如为空,只会在组件初始化的时候执行。

 

 // 省略部分代码
  const useMount = (fn: () => void) => {
  // 省略部分代码
  // 单纯就在 useEffect 基础上封装了一层
  useEffect(() => {
  fn?.();
  }, []);
  };
  export default useMount;

  useUnmount

  useUnmount,组件卸载(unmount)时执行的 Hook。

  useEffect 可以在组件渲染后实现各种不同的副作用。有些副作用可能需要清除,所以需要返回一个函数,这个函数会在组件卸载的时候执行。

  const useUnmount = (fn: () => void) => {
  const fnRef = useLatest(fn);
  useEffect(
  // 在组件卸载(unmount)时执行的 Hook。
  // useEffect 的返回值中执行函数
  () => () => {
  fnRef.current();
  },
  [],
  );
  };
  export default useUnmount;

  useUnmountedRef

  获取当前组件是否已经卸载的 Hook。

  通过判断有没有执行 useEffect 中的返回值判断当前组件是否已经卸载。

 

 // 获取当前组件是否已经卸载的 Hook。
  const useUnmountedRef = () => {
  const unmountedRef = useRef(false);
  useEffect(() => {
  unmountedRef.current = false;
  // 如果已经卸载,则会执行 return 中的逻辑
  return () => {
  unmountedRef.current = true;
  };
  }, []);
  return unmountedRef;
  };
  export default useUnmountedRef;

  Effect

  这里只会讲官方文档Effect下面的几个,有部分是定时器、防抖节流等,咱们后面的系列具体分析。

  useUpdateEffect 和 useUpdateLayoutEffect

  useUpdateEffect 和 useUpdateLayoutEffect 的用法跟 useEffect 和 useLayoutEffect 一样,只是会忽略首次执行,只在依赖更新时执行。

  实现思路:初始化一个标识符,刚开始为 false。当首次执行完的时候,置为 true。只有标识符为 true 的时候,才执行回调函数。

  // 忽略首次执行
  export const createUpdateEffect: (hook: effectHookType) => effectHookType =
  (hook) => (effect, deps) => {
  const isMounted = useRef(false);
  // for react-refresh
  hook(() => {
  return () => {
  isMounted.current = false;
  };
  }, []);
  hook(() => {
  // 首次执行完时候,设置为 true,从而下次依赖更新的时候可以执行逻辑
  if (!isMounted.current) {
  isMounted.current = true;
  } else {
  return effect();
  }
  }, deps);
  };

  useDeepCompareEffect和useDeepCompareLayoutEffect

  用法与 useEffect 一致,但 deps 通过 lodash isEqual 进行深比较。

  通过 useRef 保存上一次的依赖的值,跟当前的依赖对比(使用 lodash 的 isEqual),并将对比结果作为 useEffect 的依赖项,从而决定回调函数是否执行。

   const depsEqual = (aDeps: DependencyList, bDeps: DependencyList = []) => {
  return isEqual(aDeps, bDeps);
  };
  const useDeepCompareEffect = (effect: EffectCallback, deps: DependencyList) => {
  // 通过 useRef 保存上一次的依赖的值
  const ref = useRef<DependencyList>();
  const signalRef = useRef<number>(0);
  // 判断最新的依赖和旧的区别
  // 如果相等,则变更 signalRef.current,从而触发 useEffect 中的回调
  if (!depsEqual(deps, ref.current)) {
  ref.current = deps;
  signalRef.current += 1;
  }
  useEffect(effect, [signalRef.current]);
  };

  useUpdate

  useUpdate 会返回一个函数,调用该函数会强制组件重新渲染。

  返回的函数通过变更 useState 返回的 state,从而促使组件进行更新。

  import { useCallback, useState } from 'react';
  const useUpdate = () => {
  const [, setState] = useState({});
  // 通过设置一个全新的状态,促使 function 组件更新
  return useCallback(() => setState({}), []);
  };
  export default useUpdate;

  总结与思考

  写代码要清楚知道,组件的生命周期是怎样的,还有代码的执行顺序、执行的时机是怎样的。

  在 Function Component 中,使用 useEffect/useLayoutEffect 完成了 Class Components 生命周期的职责。ahooks 这就是的代码执行时机,要是添加hook,就可以让代码具有可读性以及逻辑更加清晰。



文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128256.html

相关文章

  • ahooks正式发布React Hooks工具库

      起因  社会在不断的向前,技术也在不断的完善进步。从 React Hooks 正式发布到现在,越来越多的项目正在使用 Function Component 替代 Class Component,Hooks 这一新特性也逐渐被广泛的使用。 这样的解析是不是很熟悉,在日常中时常都有用到,但也有一个可以解决这样重复的就是对数据请求的逻辑处理,对防抖节流的逻辑处理等。 另一方面,由于 Hoo...

    3403771864 评论0 收藏0
  • React官方团队实例原生Hook闭包陷阱

      陷进到处都是啊!本篇文章就说说Hooks使用时存在所谓的闭包陷阱,看看下面代码:  functionChat(){   const[text,setText]=useState('');   constonClick=useCallback(()=>{   sendMessage(text);   },[]);   return<SendButtononClick=...

    3403771864 评论0 收藏0
  • 解析ahooks整体架构及React工具库源码

     这是讲 ahooks 源码的第一篇文章,简要就是以下几点:  加深对 React hooks 的理解。  学习如何抽象自定义 hooks。构建属于自己的 React hooks 工具库。  培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。  注:本系列对 ahooks 的源码解析是基于v3.3.13。自己 folk 了一份源码,主要是对源码做了一些解读,可见详情。  第一篇主要介绍 a...

    3403771864 评论0 收藏0
  • 详解ahooks解决React闭包问题方法

      想必大家都能看得懂的源码 ahooks 整体架构篇,且可以使用插件化机制优雅的封装你的请求hook,现在我们就探讨下ahooks 是怎么解决 React 的闭包问题的?。  React 的闭包问题  先来看一个例子:  importReact,{useState,useEffect}from"react";   exportdefault()=>{   const[c...

    3403771864 评论0 收藏0
  • 关于ahooks封装cookie localStorage sessionStorage方法

      之所以讲这篇文章主要是为了加深对 React hooks 的理解。  因此,先要学习如何抽象自定义 hooks。构建属于自己的 React hooks 工具库。  且培养阅读学习源码的习惯,工具库是一个对源码阅读不错的选择。  现在看下ahooks 是怎么封装 cookie/localStorage/sessionStorage 的。  cookie  ahooks 封装了 useCookie...

    3403771864 评论0 收藏0

发表评论

0条评论

3403771864

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<