likes
comments
collection
share

react hook的最强拓展——useEffect篇

作者站长头像
站长
· 阅读数 15

前言

随着react16.8的发布,hook新特性随之而来,hook的到来让function组件焕发出强大的能力,足矣取代之前的class组件。函数式组件依靠useState、useEffect等hook实现变量状态维持、抽离副作用等功能。虽然原生的useEffect具有强大的功能,但是那些常用的写法每次都要手动复现一次,不但影响开发效率,而且容易出错。

下面我会给大家推荐一个npm第三方库,它将与有关useEffect常用的写法都封装起来,绝对可以助力你的开发,

让你的开发如鱼得水。

这个库的名称是pluto-hooks,在npm官网上也可以搜索到其相关信息,下面是npm地址

https://www.npmjs.com/package...

此项目大部分hook都是和useEffect有关,当然也有其他,开发者们可以自行选择使用,下面介绍一下此库的使用方法

安装

首先先要在react项目中安装,推荐使用yarn安装

yarn

yarn add pluto-hooks

npm

npm i pluto-hooks

使用

在react项目中直接引用即可

import { useEffectOnece } from "pluto-hooks";

useEffectOnece(() => {
  console.log("触发");
});

前置知识

要了解下面的用法,你得对react组件(这里只用函数式组件)及hook有一些了解

什么时候会触发组件渲染
  1. 组件中的状态改变的时候,

    • useState改变状态
    • 子组件调用父组件的方法使父组件的状态改变
    • props改变
  2. 父组件重新渲染
  3. 生成该组件的工厂函数重新执行(如改工厂函数放在useCallback中,依赖值发生变化)
useEffect的两个参数
  1. effect

    该参数接收一个函数,该函数返回一个销毁函数(指return返回的cleanup函数),如果 useEffect 第一个参数传入 async,返回值则变成了 Promise,会导致 react 在调用销毁函数的时候报错 :function.apply is undefined

  2. deps

    改参数接收一个数组,数组中存放useEffect的依赖值,当页面重新渲染时react会对比前一个deps和新deps,这里是用的浅比较对deps中的每个元素进行比较,所以当deps=[{}]时effect每次都会执行,因为{} !=== {}

hooks介绍

useCountUpdateEffect

第n次渲染并且deps变化才执行effect

有时候我们在项目开发中需要在组件渲染到固定次数时触发某个方法,如使用input输入文本时,每次敲击键盘都会触发一次render,我们可以使用useCountUpdateEffect控制effect的触发时机

注:第一次渲染也算一次

示例
import React, { useState } from "react";
import useCountUpdateEffect from "../index";

export default () => {
    const [text, setText] = useState('');

  function inputChange(e){
    setText(e.target.value)
  }

    useCountUpdateEffect(() => {
        console.log('useCountUpdateEffect执行');
    },10);

    return (
        <div>
            <p>{text}</p>
            <p>
                <input type="text" onChange={inputChange} />
            </p>
        </div>
    );
};

react hook的最强拓展——useEffect篇

useRangeUpdateEffect

在组件渲染次数为[range[0],range[1]]之间执行

此hook为useCountUpdateEffect的升级版,有时候我们不一定要在某个渲染次数时触发回调函数,而是要在某个范围内连续触发

其中第二个参数传入一个数组range,range[0]为左边界,range[1]为右边界,若传入[,right],则默认为[0,right],如果传入[left,],则大于left(包括left)的渲染次数都会触发effect,若传入[],则与useEffect没有区别

第三个参数为依赖deps

示例
import React, { useState } from "react";
import useRangeUpdateEffect from "../index";

export default () => {
    const [text, setText] = useState('');

  function inputChange(e){
    setText(e.target.value)
  }

    useRangeUpdateEffect(() => {
        console.log('useRangeUpdateEffect');
    },[5,10]);

    return (
        <div>
            <p>{text}</p>
            <p>
                <input type="text" onChange={inputChange} />
            </p>
        </div>
    );
};

react hook的最强拓展——useEffect篇

同样的,这里也会算上初始渲染,如果想不考虑首次渲染,可以调整第二个参数的范围

useCompareEffect

type {
    effect:EffectCallback,
    deps:DependencyList,
    depsEqual:(oldDeps:DependencyList,nextDeps:DependencyList) => boolean
}

正如我们前置知识讲到的,useEffect默认只会对deps进行浅比较,但是使用useCompareEffect我们就可以自定义deps的比较

第三个参数为比较函数,depsEqual的第一个参数是旧的deps数组,第二个参数为新的deps数组,该函数返回一个boolean值,为true时不执行effect,反之执行

示例
import React, { useState } from "react";
import useCompareEffect from "../index"

export default function demo() {
  const [count1, setCount1] = useState(0)
  const [count2, setCount2] = useState(0)
  const [count, setCount] = useState(0)

  const compareFn = (old,next) => {
    console.log('old,next: ', old,next);
    return old[1] === next[1]
  }

  useCompareEffect(() => {
    // 只有count2改变时会触发
    setCount(state => state + 1)
  }, [count1, count2],compareFn)

  return (
    <div>
      <h2>{count}</h2>
      <h2>{count1}</h2>
      <h2>{count2}</h2>
      <button onClick={() => {setCount1(state => state + 1)}}>count1</button>
      <button onClick={() => {setCount2(state => state + 1)}}>count2</button>
    </div>
  )
}

react hook的最强拓展——useEffect篇

useDeepCompareEffect

此hook基于上面的useCompareEffect,当组件重新渲染时执行useDeepCompareEffect,该hook将对deps进行深比较,若相等则执行effect

type {
    effect:EffectCallback,
    deps:DependencyList,
}

useAsyncEffect

看过前置知识的小伙伴可能还记得,useEffect的第一个参数是不能传入async函数的,如果真的要使用async函数,可以调用useAsyncEffect

示例
import React, { useState } from "react";
import useAsyncEffect from "../index"

export default () => {

  const fn = () => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve()
      }, 3000)
    })
  }

  useAsyncEffect(async () => {
    console.log('等待...');
    await fn()
    console.log('完成');
  }, []);
};

以上代码将会在组件初始化时显示”等待...“,3秒后显示”完成“

useDebounceFn

处理防抖函数

const {
  run,
  cancel,
  flush
} = useDebounceFn(
  fn: (...args: any[]) => any,
  options?: Options
);

run, cancel, flush为可执行函数

run:开始防抖地执行fn,传入run的参数会传到fn

cancel:取消执行fn

flush:立即执行fn,不用等到wait时间结束

useDebounceEffect

type {
    effect:EffectCallback,
    deps?:DependencyList,
    options:DebounceOptions
}

将传入的Effect带上防抖,options可以配置防抖参数

options参数(默认值):

[options.wait=1000] (number): 等待时间,单位为毫秒。
[options.leading=false] (boolean): 指定在延迟开始前调用。
[options.maxWait] (number): 设置 func 允许被延迟的最大值。
[options.trailing=true] (boolean): 指定在延迟结束后调用。

useThrottleFn

处理节流函数的hook

const {
  run,
  cancel,
  flush
} = useThrottleFn(
  fn: (...args: any[]) => any,
  options?: Options
);

options参数:

[options.wait=1000] (number): 等待时间,单位为毫秒。
[options.leading=true] (boolean): 指定调用在节流开始前。
[options.trailing=true] (boolean): 指定调用在节流结束后。

run, cancel, flush为可执行函数

run:开始防抖地执行fn,传入run的参数会传到fn

cancel:取消执行fn

flush:立即执行fn,不用等到wait时间结束

useThrottleEffect

将传入的Effect带上节流功能,options可以配置节流参数

type {
    effect:EffectCallback,
    deps:DependencyList,
    options:ThrottleOptions
}

options参数:

[options.wait=1000] (number): 等待时间,单位为毫秒。
[options.leading=true] (boolean): 指定调用在节流开始前。
[options.trailing=true] (boolean): 指定调用在节流结束后。

useEffectOnce

只在第一次渲染时执行

type {
    effect:EffectCallback,
}

useFirstMountState

判断改组件是否是第一次渲染,返回Boolean

示例
import React, { useEffect, useState } from "react";
import useFirstMountState from "../index"

export default () => {
  const [count, setCount] = useState(0);
    const isfirst = useFirstMountState()
    console.log('isfirst: ', isfirst);

  return (
    <div>
      <div>first:{isfirst}</div>
      <p>
        <button type="button" onClick={() => setCount((c) => c + 1)}>
          reRender
        </button>
      </p>
    </div>
  )
}

react hook的最强拓展——useEffect篇

可以看到后面点击reRender时useFirstMountState()都是返回false

useUpdateEffect

非首次渲染时执行

type {
    effect:EffectCallback,
    deps:DependencyList,
}

对这个项目的介绍就到这里啦,如果后面有更新会继续的,此项目的github地址https://github.com/plutoLam/h...,使用bruce-app搭建,rollup进行打包