pluto-hooks
一个好用的react hook工具库
前言
随着react16.8的发布,hook新特性随之而来,hook的到来让function组件焕发出强大的能力,足矣取代之前的class组件。函数式组件依靠useState、useEffect等hook实现变量状态维持、抽离副作用等功能。虽然原生的useEffect具有强大的功能,但是那些常用的写法每次都要手动复现一次,不但影响开发效率,而且容易出错,所以笔者将有关useEffect常用的写法都封装起来,让你的开发如鱼得水。
此项目大部分hook都是和useEffect有关,当然也有其他,开发者们可以自行选择使用
后续会继续更新更多hook的拓展功能!!
安装
yarn
yarn add pluto-hooks
npm
npm i pluto-hooks
使用
import { useEffectOnece } from "pluto-hooks";
useEffectOnece(() => {
console.log("触发");
});
hooks介绍
effect相关
useCountUpdateEffect
第n次渲染并且deps变化才执行effect
type {
effect:EffectCallback,
n:number,
deps?:DependencyList
}
useRangeUpdateEffect
在组件渲染次数为[range[0],range[1]]之间执行
type {
effect:EffectCallback,
deps:DependencyList,
range:number[]
}
useCompareEffect
type {
effect:EffectCallback,
deps:DependencyList,
depsEqual:(oldDeps:DependencyList,nextDeps:DependencyList) => boolean
}
第三个参数为比较函数,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
当组件重新渲染时执行useDeepCompareEffect,该hook将对deps进行深比较,若相等则执行effect
type {
effect:EffectCallback,
deps:DependencyList,
}
useAsyncEffect
type {
effect:EffectCallback,
deps?:DependencyList
}
普通的useEffect的第一个参数是不能传入一个异步函数的,理由是 effect function 应该返回一个销毁函数(effect:是指return返回的cleanup函数),如果 useEffect 第一个参数传入 async,返回值则变成了 Promise,会导致 react 在调用销毁函数的时候报错 :function.apply is undefined。
调用useAsyncEffect
,effect function即可可以传入异步函数
示例
import { useAsyncEffect } from "pluto-hooks"
function App(){
useAsyncEffect(async () => {
// 进行异步操作
},[])
}
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,
}
useUpdateEffect
非首次渲染时执行
type {
effect:EffectCallback,
deps:DependencyList,
}
leftCycle相关
useFirstMountState
判断改组件是否是第一次渲染,返回Boolean
示例
import { useFirstMountState } from "pluto-hooks"
function App(){
const isFirst = useFirstMountState()
if(isFirst){
// 第一次渲染要执行的
}
}
useMount
只在第一次渲染执行传入的函数
type {
fn: (...args: any) => void
}
useUnmount
在组件卸载时执行传入的函数
type {
fn: (...args: any) => void
}
useUnmountedRef
维护一个ref并返回,当组件已经卸载时为true,否则为false
- 经常用于阻止组件卸载后副作用继续执行
example:
import useUnmountedRef from "../index";
import React, { useEffect } from "react";
// 加载后马上按button,效果是三秒后没有执行setTimeout的异步操作
const MyComponent = () => {
const unmountedRef = useUnmountedRef();
useEffect(() => {
setTimeout(() => {
if (!unmountedRef.current) { // 当前组件卸载后则不再执行某些异步操作
console.log("component is alive");
}
}, 3000);
}, []);
return <p>Hello World!</p>;
};
state相关
useBoolean
管理一个boolean类型的state,返回当前state和4个方法
toggle:将取反
setTrue:将state设为true
setFalse:将state设为false
const [ state, { toggle, setTrue, setFalse }] = useBoolean(
initState?: boolean,
);
useCookie
设置并管理一个cookie的状态
若要将cookie删除,调用useCookie()
或useCookie(undefined)
即可
export interface cookieOPtionsType {
domain?: string,
path?: string,
day?: number, // 表示过期天数,-1表示立即过期
secure?: boolean,
sameSite?: "strict" | "lax" | "none"
}
const [cookie, setCookie] = useCookie(
key: string,
value?: string,
defaultOptions: cookieOPtionsType
)
useCookies
管理当前全部的cookie
getCookie:const cookie = getCookie(key:string)
setCookie: setCookie(key: string, value: string, options: cookieOPtionsType= {})
removeCooikeItem: removeCooikeItem(key:string)
getAllCookie:获取所有的cookie
interface cookieType {
[key: string]: string
}
const cookieArr = getAllCookie():cookieType
const {
getCookie,
setCookie,
removeCooikeItem,
getAllCookie
} = useCookies()
useGetState
可以跳出当前闭包环境获取state的最新值
返回数组的前两个元素和useState返回的没有差别,第三个函数可以实时获取state的最新值
const [state, setState, getState] =
useGetState<S>(initValue: S | (() => S))
useLocalStorageState
设置并管理一个localStorage
defaultValue为初始值
serializer:默认为JSON.stringify
可以自定义序列化函数,每次设置值都会存储序列化后的值
deserializer:默认为JSON.parse
可以自定义反序列化函数,每次取值都会进行反序列化
interface Options<T> {
defaultValue?: T | (() => T);
serializer?: (value: T) => string;
deserializer?: (value: string) => T;
}
const [state, setState] =
useLocalStorageState<T>(key: string, options: Options<T>)
useSessionStorageState
与useLocalStorageState一样
useMap
维护一个map
可以选择传入的参数为一个二维数组作为初始值,如
[
["key1", "hello world"],
[123, "number type"]
]
const [map, { set, setAll, remove, reset, get }] =
useMap<K, T>(initialValue?: Iterable<readonly [K, T]>)
set:添加键值对set(key: any, value: any): void
setAll:重置该map,传入二维数组
remove:移除一对键值对remove(key: any): void
reset:重置为初始值
get:传入一个key获取value
useSet
维护一个set
传入一个数组作为初始值
const [state, { add, remove, reset }] =
useSet<T>(initValue?: Iterable<T>)
add:接收一个参数,为set添加值
remove:接收一个key,移除它
reset:重置为初始值
usePrevious
维护state上次的值
传入一个状态state
const previous = usePrevious<T>(state: T): T
useSetState
管理 object 类型 state 的 Hooks,用法与 class 组件的 this.setState
基本一致。
可以直接合并新旧对象
const [state, setState] = useSetState(initialState)
useToggle
维护两个状态,可以相互转换
- 若不传入参数,则用法和
useBoolean
一样 - 若值传入第一个参数,right则取left的反值(!left)
toggle:换到另一个状态
set:修改状态值
setLeft:将状态值修改为defaultValue
setRight:将状态值修改为reverseValue
const [state, { toggle, set, setLeft, setRight }] =
useToggle(defaultValue, reverseValue)
useUrlState
维护url的params参数,管理一个object对象,基于上面的useSetState
若要删除某个参数,将其设为undefined即可
interface paramsType {
[key: string]: string
}
interface optionsType {
navigateMode: "push" | "replace"
// push 使用history.pushState()这个API
// replace 使用history.replaceState()这个APi
}
const [state, setState] =
useUrlState(initParams: paramsType, options: optionsType)
other
useEvent
使useCallback的依赖没有发生变化的情况下,它的函数能取最新的props和state
example:
export default function demo1() {
const [count, setCount] = useState(1);
const fn = useEvent(() => {
setCount(state => state + 1);
console.log(count);
}, []);
return (
<button onClick={() => { fn(); }}>Click</button>
);
}
如果fn
使用useCallback包裹,那么当点击Click时打印出来的count每次都是1,这里有两个原因
-
useState
是异步的,setCount后state不会马上发生变化 - 当第二次点击时,因为被useCallback包裹,fn的状态还是停留在最初渲染时,而且没有依赖,所以fn的引用永远不会改变,所以fn里面的state永远都是1
使用useEvent
包裹后,state即可获取到最新的上下文