阅读 193

按钮和异步状态和huse

省流助手(主题)

  • 常见的按钮与异步事件的使用

  • 使用useActionPending改造

  • huse,一款react-hooks组件库

Button & Loading

当点击按钮触发异步请求时,通常会有如下示例

1121-2.gif

实现上述过程的思路之一:

  1. 设置初始值为false的状态isLoading

  2. 在调用异步方法之前,将isLoading设置为true

  3. 在调用异步方法之后(包括异常状态),将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>
    );
};复制代码

好耶!大功完成?

且慢,先看看其他场景的适用性

如果该按钮能在不同场景调用不同的异步请求呢?

比如同一个按钮能在‘编辑’和‘新增’两个场景下被分别调用

继续按上面的逻辑,则需要维护两个状态:isEditLoadingisAddLoading

然后分别在调用前后修改状态,如果有更多的场景,则会以下代码:

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


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐