关于前端:react-hook的最强拓展useEffect篇

55次阅读

共计 5197 个字符,预计需要花费 13 分钟才能阅读完成。

前言

随着 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>
    );
};

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>
    );
};

同样的,这里也会算上初始渲染,如果想不思考首次渲染,能够调整第二个参数的范畴

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>
  )
}

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>
  )
}

能够看到前面点击 reRender 时 useFirstMountState() 都是返回 false

useUpdateEffect

非首次渲染时执行

type {
    effect:EffectCallback,
    deps:DependencyList,
}

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

正文完
 0