1、useRequest
useRequest
是一个强大的异步数据管理的 Hooks,React 项目中的网络请求场景使用 useRequest
就够了。
useRequest
通过插件式组织代码,核心代码极其简单,并且可以很方便的扩展出更高级的功能。目前已有能力包括:
- 自动请求/手动请求
- 轮询
- 防抖
- 节流
- 屏幕聚焦重新请求
- 错误重试
- loading delay
- SWR(stale-while-revalidate)
- 缓存
简单使用:
TypeScript
import { useRequest } from 'ahooks';
import React from 'react';
function getUsername(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(xxx);
}, 1000);
});
}
export default () => {
const { data, error, loading } = useRequest(getUsername);
if (error) {
return <div>failed to load</div>;
}
if (loading) {
return <div>loading...</div>;
}
return <div>Username: {data}</div>;
};
//本段代码中,加载此页面时候会自动调用该getUserName()方法
const { data, error, loading } = useRequest(getUsername)
//此条代码含义为
// 1、data:请求发送完成之后返回的结果
// 2、error:请求失败,或者发生错误
// 3、loading:请求是否完成,请求完成为flse,未完成为true
//页面加载时候带参请求
const { data } = useRequest(()=>getUsername( { aaa : xxx }))
//需要进行手动控制是否调用则需要添加一个{ manual:true } 参数,以及run/runAsync方法
const { loading, run } = useRequest(changeUsername, {
manual: true
});
//在后续代码中通过调用run()方法,即可调用该请求,假设请求过多,则需要给方法取个别名
const { loading, run : getUsernameRun } = useRequest(changeUsername, {
manual: true
});
//runAsync 用法与 run类似,但是异步调用,按需使用
//完整Api
const {
loading: boolean, //请求是否完成
data?: TData, //请求返回结果
error?: Error, //请求抛出的异常
params: TParams || [], //请求参数数组 例:run(1,2,3) 为 param = [1,2,3]
run: (...params: TParams) => void, //手动触发调用请求,异常自动处理通过onErrot()
runAsync: (...params: TParams) => Promise<TData>, //与run一致,返回Promise,自行处理异常
refresh: () => void, //使用上次的param,重新调用run方法
refreshAsync: () => Promise<TData>, //使用上次的param,重新调用runAsync方法
mutate: (data?: TData | ((oldData?: TData) => (TData | undefined))) => void,//直接修改data
cancel: () => void, //忽略当前Promise的响应
} = useRequest<TData, TParams>(
service: (...args: TParams) => Promise<TData>, //请求路径
{
manual?: boolean, //是否手动触发请求接口
defaultParams?: TParams, //首次执行时候默认传递给接口的参数
onBefore?: (params: TParams) => void, //请求执行前触发
onSuccess?: (data: TData, params: TParams) => void, //请求执行成功(resolve)之后触发
onError?: (e: Error, params: TParams) => void, //请求失败reject触发
onFinally?: (params: TParams, data?: TData, e?: Error) => void, //请求执行完成之后触发
}
);
2、useState
用法与class的this.setState基本一致
TypeScript
//使用案例
const [state, setState] = useSetState<State>({
hello: '',
count: 0,
});
//取值
{ state }
//设置值,设置hello
{ setState({ hello : 'haha' }) } //此时state中的hello值为 haha
//因为useState为异步的,有时候使用会需要第一时间更新数据,这个时候可以采用一个中间值来转换使用
const tempParam = { ...state, keywords: params?.orderKeyWord }
//此时可以使用temParam作为参数来使用,再使用setState重新赋值即可
setState(tempParam)
//整体Api
const [state, setState] = useSetState<T extends Record<string, any>>(
initialState: T = {} as T
): [T, (patch: Partial<T> | ((prevState: T) => Partial<T>)) => void]
3、useEffect *
useEffect用于处理组件中的副作用,用来取代生命周期函数
用法:在react中,可以在生命周期中执行副作用操作,在react hooks中,可以在useEffect中执行副作用操作。
执行时机,可以看作
1、componentDidMount
2、componentDidUpdate
3、componentWillUnmount
这三个生命周期函数组合,即在这三个时候都会执行一次
参数用法(无需清除的副作用操作:直接在useEffect( method )中传入操作函数method即可)
useEffect()有两个参数:
1、是要执行的参数;
2、依赖项数组(根据需求判断是否需要填写),判断数组里的变量是否发生变化来决定是否执行函数
TypeScript
useEffect (要执行的参数,依赖数组)
只写第一个参数:
TypeScript
//1.若不写第二个参数,函数操作每次都会执行 useEffect(method)
const [ count,setCount ]= useState(0)
useEffect(()=>{
console.log('第',{count},'次')
}) //此处并未添加第二个参数
return (
<div>
<h2>点击了{count}次</h2>
<button onClick={ () => {setCount( count + 1 )}}>click me</button>
</div>
);
启动输出结果:
点击按钮之后执行结果
只写第二个参数,且为空数组:
TypeScript
//2.有第二个参数但数组为空,则副作用仅在组件挂载和卸载时执行。useEffect( ()=>{doSomeThing}, [])
const [ count,setCount ]= useState(0)
useEffect(()=>{
console.log('第',{ count : count+1 },'次')
},[]) //此处添加了一个空数组
return (
<div>
<h2>点击了{count}次</h2>
<button onClick={ () => {setCount( count + 1 )}}>click me</button>
</div>
);
启动输出结果:
点击之后输出:
小结:可见假如给到第二个参数为空数组时候,useEffect()只在页面加载完成之后执行一次,而后不会再次执行
第二个参数为可变数组:
TypeScript
//3.若有第二个参数且数组里的变量不为空,则变量有变化时执行副作用操作,无变化则不执行.
//useEffect(()=>{doSomeThing}, [a]), a 变化时执行(任意一个或全部变化)
const [ count,setCount ]= useState(0);
useEffect(()=>{
console.log('第',{ count : count+1 },'次')
},[count]);
return (
<div>
<h2>点击了{count}次</h2>
<button onClick={ () => {setCount( count + 1 );}}>click me</button>
</div>
);
启动输出结果:
点击之后执行结果:
参数用法(需要清除的副作用操作:比如监听事件,useEffect( method )在method中添加了一个监听事件,取消监听只需要在method里return一个取消监听的函数即可)
不添加第二个参数
TypeScript
//未传递第二个参数
const [ count,setCount ]= useState(0);
useEffect(()=>{
console.log('加载或者数据变化执行了')
return ()=>{
console.log('执行了清除函数')
setCount(0)
}
});
return (
<div>
<h2>点击了{count}次</h2>
<button onClick={ () => {setCount( count + 1 );}}>click me</button>
</div>
);
执行结果:
点击之后执行结果:
因为useEffect中再次执行了setCount,所以导致又使用了一次useEffect,即加载了两次
添加第二个参数,且第二个参数为空数组
TypeScript
//添加[]空数组为第二个函数,且有return时,切换组件时才会只执行清除函数
//否则只在加载页面加载一次useEffect,且不执行清除函数
添加第二个参数,且第二个数组监听数据变化
TypeScript
//数据加载时候不执行清除函数,只执行一次useEffect
//点击事件执行时候,执行useEffect,且会执行清除函数
//切换到别的组件,也会执行一次清除副作用函数
const [ count,setCount ]= useState(0);
useEffect(()=>{
console.log('加载或者数据变化执行了')
return ()=>{
console.log('执行了清除函数')
setCount(0)
}
},[count]);
return (
<div>
<h2>点击了{count}次</h2>
<button onClick={ () => {setCount( count + 1 );}}>click me</button>
</div>
);
总结:
-
return
- 第二个参数是副效应函数的依赖项,只有该变量发生变化的时候,副效应函数才执行;
- 第二个参数为空数组时候,只在页面加载时候执行一次。
-
当有
return
- 如果没有第二个参数,页面数据发生变化时候会执行,且return也会执行;
- 如果第二个参数是一个空数组,页面加载时候执行一次useEffect,不执行其中return,在组件切换之后会执行return;
- 如果有依赖项,依赖项发生变化的时候,先执行return,而后再执行useEffect内容。