按钮和异步状态和huse
省流助手(主题)
常见的按钮与异步事件的使用
使用
useActionPending
改造huse
,一款react-hooks组件库
Button & Loading
当点击按钮触发异步请求时,通常会有如下示例
实现上述过程的思路之一:
设置初始值为
false
的状态isLoading
在调用异步方法之前,将
isLoading
设置为true
在调用异步方法之后(包括异常状态),将
isLoading
设置为false
代码实现如下,比较简单
// 延迟一秒的异步请求 const fnRequest = (): Promise<string> => new Promise((resolve) => { setTimeout(() => resolve('success!'), 1000); });复制代码
import {Button, message} from 'antd'; import {useCallback, useState} from 'react'; const App = () => { const [isLoading, setLoading] = useState(false); const handleClick = useCallback(async () => { setLoading(true); try { const res = await fnRequest(); message.success(res); } finally { setLoading(false); } }, []); return ( <Button onClick={handleClick} loading={isLoading} type="primary"> click </Button> ); };复制代码
好耶!大功完成?
且慢,先看看其他场景的适用性
如果该按钮能在不同场景调用不同的异步请求呢?
比如同一个按钮能在‘编辑’和‘新增’两个场景下被分别调用
继续按上面的逻辑,则需要维护两个状态:
isEditLoading
和isAddLoading
然后分别在调用前后修改状态,如果有更多的场景,则会以下代码:
const [isScene1Loading, setScene1Loading] = useState(false); const [isScene2Loading, setScene2Loading] = useState(false); const [isSceneNLoading, setSceneNLoading] = useState(false); ... try { // 设置3个状态为true } finally { // 设置3个状态为false } ... <Button loading={isScene1Loading || isScene2Loading || isSceneNLoading}/>复制代码
当重复或类似的代码过多,就得考虑其他方法来重构这个功能了
分析可知,我们设置了一组状态去追踪一种异步请求的过程
因此,如果有能自动判断异步请求是否完成的标识,就能简化这个过程
当然有了,它就是
[useActionPending] github.com/ecomfe/reac…
使用useActionPending
管理异步请求状态
首先简单看下如何使用
AsyncFunction
就是我们需要管理的异步函数的类型,作为唯一参数传给useActionPending
然后返回新的异步函数(原函数+计数功能),和一个数字(记录异步函数正在被调用的次数)
type AsyncFunction = (...args: any[]) => Promise<any>; function useActionPending<A extends AsyncFunction>(action: A): [A, number]复制代码
因此可知,返回的数字不为0代表正在请求,为0代表请求完毕;即
isLoading = pendingCount !== 0
然后可得新版代码逻辑如下:
import {Button, message} from 'antd'; import {useCallback} from 'react'; import {useActionPending} from '@huse/action-pending'; const App = () => { const [request, pendingCount] = useActionPending(fnRequest); const isLoading = pendingCount !== 0; const handleButtonClick = useCallback(async () => { const res = await request(); message.success(res); }, []); return ( <Button onClick={handleClick} loading={isLoading} type="primary"> click </Button> ); };复制代码
可以发现代码简洁了一些,体现在处理异步函数的方法里,不用再管理其他状态
有兴趣的小伙伴可以查看一样
useActionPending
的源码实现,代码非常精简但非常巧妙~
这次的分享就到这里了,欢迎给这个好用的react-hook组件库打星哦
作者:别管派蒙了
链接:https://juejin.cn/post/7032937186081112077