React Hook 也有生命周期?你知道吗?

895 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

前言

React 16.8 更新之后,函数式组件已逐步取代类组件的地位,所以在这里介绍一个高质量可靠的 React Hooks 库:ahooks

官方的介绍:ahooks,发音 [eɪ hʊks],是一套高质量可靠的 React Hooks 库。在当前 React 项目研发过程中,一套好用的 React Hooks 库是必不可少的,希望 ahooks 能成为您的选择。

就在前不久 ahooks 有 V2 升级到了 v3,有感兴趣的朋友可以看看:ahoos官网

本菜鸟也整体将 ahooks 看了下,感觉有种 食之无味,弃之可惜的感觉,当然这里面有些 Hook 还是 非常nice 的,有句话说得好:你可以不会,但你不能不知道,万一哪天用到了呢

所以学习 ahooks 是非常有必要的,请卷起来!

为了方便介绍好的 Hook,我们使用 ⭐️ 做个标记

⭐️:一般; ⭐️⭐️:重要; ⭐️⭐️⭐️:很重要;

具体演示示例: Domesy/ahook

0a3c524f2805476ab2e694aeb035ec57_tplv-k3u1fbpfcp-watermark.webp

生命周期

本文主要介绍:useMount、 useUnmount、useUpdateEffect、 useUpdate、useTrackedEffect、 useThrottleEffect、useDebounceEffect 七个Api

在React 16.8之前,类组件和函数组件的区别就是有无状态,那么在函数式出来后,有没有使 Hook 也具有相同的钩子呢?

其实 ahooks 就能解决这个问题。接下看看 ahooks 是如何使用的。如果对类组件生命周期感兴趣的同学可以看看:请你说下React的生命周期(16.0和16.4)?(面试还是会问到的(● ̄(エ) ̄●))

useMount(装载)和 useUnmount(卸载)

推荐指数:⭐️

useMount :组件装载的时候调用,类似于 class 组件的 componentDidMount useUnmount :组件卸载的时候调用,类似于 class 组件的 componentWillUnmount

示例代码:

  import React from 'react';
  import { Button, message } from 'antd';
  import { useToggle, useMount, useUnmount } from 'ahooks';

  const Test = () => {
    useMount(() => {
      message.info('装载');
    });

    useUnmount(() => {
      message.info('卸载');
    });

    return <div>初始页面</div>;
  };


  const Mock: React.FC<any> = () => {
    const [state, { toggle }] = useToggle(false);

    return (
      <>
        <button type="button" onClick={() => toggle()}>
          {state ? '卸载' : '装载'}
        </button>
        {state && <Test />}
      </>
    );
  };

  export default Mock;

useUpdateEffect 更新

推荐指数:⭐️⭐️

useUpdateEffect:在使用的时候与 useEffect 一致,不同时是 忽略了首次渲染

代码示例

  import React, { useState, useEffect } from 'react';
  import { Button, message } from 'antd';
  import { useUpdateEffect } from 'ahooks';

  const Mock: React.FC<any> = () => {
    const [count, setCount] = useState(0);
    const [effectCount, setEffectCount] = useState(0);
    const [updateEffectCount, setUpdateEffectCount] = useState(0);

    useEffect(() => {
      setEffectCount((c) => c + 1);
    }, [count]);

    useUpdateEffect(() => {
      setUpdateEffectCount((c) => c + 1);
    }, [count]);

    return (
      <>
        <p>使用Effect: {effectCount}</p>
        <p>使用updateEffectCount: {updateEffectCount}</p>
        <Button type='primary' onClick={() => setCount((c) => c + 1)}>
          渲染
        </Button>
      </>
    );
  };

  export default Mock;

useUpdate 强制更新

推荐指数:⭐️

useUpdate: 会返回一个函数,调用该函数会强制组件重新渲染(慎用~)

import React from 'react';
  import { Button } from 'antd';
  import { useUpdate } from 'ahooks';

  const Mock: React.FC<any> = () => {
    const update = useUpdate();

    return (
      <>
        <p>时间: {Date.now()}</p>
        <Button type='primary' onClick={() => update()}>
          强制更新
        </Button>
      </
  };

  export default Mock;

useTrackedEffect 依赖改变

推荐指数:⭐️⭐️⭐️

useTrackedEffect:用于追踪那个依赖变化触发了 useEffect的执行

这个钩子还是非常重要的,当做一个比较复杂的功能时,我们所依赖的参数较多,我们可能需要做某一项依赖改变的时候才进行触发,这个钩子就能解决我们问题

先介绍下参数:

  • changes:第几个依赖项发生了改变
  • previousDeps:依赖项当前的值
  • currentDeps:依赖项改变后的值

image.png

代码示例

  import React, { useState } from 'react';
  import { Button } from 'antd';
  import { useTrackedEffect } from 'ahooks';

  const Mock: React.FC<any> = () => {
    const [dep1, setDep1] = useState(0);
    const [dep2, setDep2] = useState(0);
    const [dep3, setDep3] = useState(0);
    const [depActiveList, setDepActiveList] = useState([false, false, false]);
    const [text, setText] = useState('第几个依赖项改变:')
    const [text1, setText1] = useState('当前的值:')
    const [text2, setText2] = useState('改变后的值:')

    const toggleDep = (index:number) => {
      const res = [...depActiveList];
      res[index] = !res[index]
      setDepActiveList(res)
    }

    useTrackedEffect((changes, previousDeps, currentDeps)=>{
      setText('第几个依赖项改变:: ' + changes);
      setText1('当前的值:: ' + previousDeps);
      setText2('改变后的值:: ' + currentDeps);
    },[dep1, dep2, dep3])

    return (
      <>
        <p><input type="checkbox" checked={depActiveList[0]} onChange={() => toggleDep(0)} />
          &nbsp;第一个值 : {dep1}</p>
          <p>
          <input type="checkbox" checked={depActiveList[1]} onChange={() => toggleDep(1)} />
          &nbsp;第二个值 : {dep2}
        </p>
        <p>
          <input type="checkbox" checked={depActiveList[2]} onChange={() => toggleDep(2)} />
          &nbsp;第三个值 : {dep3}
        </p>

        <Button type='primary' onClick={() => {
          setText('')
          setText1('')
          setText2('')
          depActiveList[0] && setDep1((c) => c + 1);
          depActiveList[1] && setDep2((c) => c + 1);
          depActiveList[2] && setDep3((c) => c + 1);
        }}>
          加 1
        </Button>
        <p>{text}</p>
        <p>{text1}</p>
        <p>{text2}</p>
      </>
    );
  };

  export default Mock;

useDebounceEffect:增强 effect 的防抖能力

推荐指数:⭐️

代码示例:

import React, { useState } from 'react';
  import { useDebounceEffect } from 'ahooks';

  const Mock: React.FC<any> = () => {
    const [value, setValue] = useState<string>('hello');
    const [records, setRecords] = useState<string[]>([]);

    useDebounceEffect( () => {
        setRecords((val) => [...val, value]);
      },
      [value],
      {
        wait: 1000,
      },
    );

    return (
      <>
        <input
          value={value}
          onChange={(e) => setValue(e.target.value)}
          placeholder="Typed value"
          style={{ width: 280 }}
        />
        <p style={{ marginTop: 16 }}>
          <ul>
            {records.map((record, index) => (
              <li key={index}>{record}</li>
            ))}
          </ul>
        </p>
      </>
    );
  };

  export default Mock;

useThrottleEffect: 增强 effect 的节流能力

推荐指数:⭐️

import React, { useState } from 'react';
  import { useThrottleEffect } from 'ahooks';

  const Mock: React.FC<any> = () => {
    const [value, setValue] = useState<string>('hello');
    const [records, setRecords] = useState<string[]>([]);

    useThrottleEffect( () => {
        setRecords((val) => [...val, value]);
      },
      [value],
      {
        wait: 1000,
      },
    );

    return (
      <>
        <input
          value={value}
          onChange={(e) => setValue(e.target.value)}
          placeholder="Typed value"
          style={{ width: 280 }}
        />
        <p style={{ marginTop: 16 }}>
          <ul>
            {records.map((record, index) => (
              <li key={index}>{record}</li>
            ))}
          </ul>
        </p>
      </>
    );
  };

  export default Mock;

End

希望跟我一样的小菜鸟亲自动手试试,加深记忆,了解就好~

其他文章