useRequest.ts 4.9 KB
Newer Older
P
Peter Pan 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/**
 * Copyright 2020 Baidu Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

17
import type {Key, SWRConfiguration, SWRResponse} from 'swr';
18 19
import {useEffect, useMemo} from 'react';

20
import type {Fetcher} from 'swr/dist/types';
21
import ee from '~/utils/event';
P
Peter Pan 已提交
22 23
import {toast} from 'react-toastify';
import useSWR from 'swr';
24

25 26 27
type RequestConfig<D, E> = SWRConfiguration<D, E, Fetcher<D>>;
type RunningRequestConfig<D, E> = Omit<RequestConfig<D, E>, 'dedupingInterval' | 'errorRetryInterval'>;
type Response<D, E> = SWRResponse<D, E> & {
28 29 30
    loading: boolean;
};

31 32
function useRequest<D = unknown, E extends Error = Error>(key: Key): Response<D, E>;
function useRequest<D = unknown, E extends Error = Error>(key: Key, fetcher: Fetcher<D> | null): Response<D, E>;
P
Peter Pan 已提交
33
function useRequest<D = unknown, E extends Error = Error>(
34 35
    key: Key,
    config: RequestConfig<D, E> | undefined
36
): Response<D, E>;
P
Peter Pan 已提交
37
function useRequest<D = unknown, E extends Error = Error>(
38 39 40 41 42 43 44 45 46 47
    key: Key,
    fetcher: Fetcher<D> | null,
    config: RequestConfig<D, E> | undefined
): Response<D, E>;
function useRequest<D = unknown, E extends Error = Error>(
    ...args:
        | readonly [Key]
        | readonly [Key, Fetcher<D> | null]
        | readonly [Key, RequestConfig<D, E> | undefined]
        | readonly [Key, Fetcher<D> | null, RequestConfig<D, E> | undefined]
48
): Response<D, E> {
49 50 51
    const key = args[0];
    const {data, error, ...other} = useSWR<D, E>(...args);

P
Peter Pan 已提交
52
    const loading = useMemo(() => !!key && data === void 0 && !error, [key, data, error]);
P
Peter Pan 已提交
53 54 55 56 57 58 59 60 61 62

    useEffect(() => {
        if (error) {
            toast(error.message, {
                position: toast.POSITION.TOP_CENTER,
                type: toast.TYPE.ERROR
            });
        }
    }, [error]);

63 64 65
    return {data, error, loading, ...other};
}

66
function useRunningRequest<D = unknown, E extends Error = Error>(key: Key, running: boolean): Response<D, E>;
P
Peter Pan 已提交
67
function useRunningRequest<D = unknown, E extends Error = Error>(
68
    key: Key,
69
    running: boolean,
70
    fetcher: Fetcher<D> | null
71
): Response<D, E>;
P
Peter Pan 已提交
72
function useRunningRequest<D = unknown, E extends Error = Error>(
73
    key: Key,
74
    running: boolean,
75
    config: RunningRequestConfig<D, E> | undefined
76
): Response<D, E>;
P
Peter Pan 已提交
77
function useRunningRequest<D = unknown, E extends Error = Error>(
78
    key: Key,
79
    running: boolean,
80 81 82 83 84 85 86 87 88
    fetcher: Fetcher<D> | null,
    config: RunningRequestConfig<D, E> | undefined
): Response<D, E>;
function useRunningRequest<D = unknown, E extends Error = Error>(
    ...args:
        | readonly [Key, boolean]
        | readonly [Key, boolean, Fetcher<D> | null]
        | readonly [Key, boolean, RequestConfig<D, E> | undefined]
        | readonly [Key, boolean, Fetcher<D> | null, RequestConfig<D, E> | undefined]
89
) {
90 91 92 93 94 95 96 97 98 99 100 101 102 103
    const [key, running, ...options] = args;
    let fetcher: Fetcher<D> | null | undefined = undefined;
    let config: RequestConfig<D, E> | undefined = undefined;
    if (options.length > 1) {
        fetcher = options[0] as Fetcher<D> | null;
        config = options[1];
    } else if (options[0] != null) {
        if (typeof options[0] === 'object') {
            config = options[0];
        } else if (typeof options[0] === 'function') {
            fetcher = options[0];
        }
    }
    const c = useMemo<SWRConfiguration<D, E, Fetcher<D>>>(
104 105
        () => ({
            ...config,
106 107 108
            refreshInterval: running ? config?.refreshInterval ?? 15 * 1000 : 0,
            dedupingInterval: config?.refreshInterval ?? 15 * 1000,
            errorRetryInterval: config?.refreshInterval ?? 15 * 1000
109
        }),
110
        [config, running]
111 112
    );

113 114 115 116 117 118 119 120 121 122 123
    const requestArgs = useMemo<
        readonly [Key, RequestConfig<D, E>] | readonly [Key, Fetcher<D> | null, RequestConfig<D, E>]
    >(() => {
        if (fetcher === undefined) {
            return [key, c];
        }
        return [key, fetcher, c];
    }, [key, fetcher, c]);

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const {mutate, ...others} = (useRequest as any)(...requestArgs);
124 125 126 127 128 129 130 131

    // revalidate immediately when running is set to true
    useEffect(() => {
        if (running) {
            mutate();
        }
    }, [running, mutate]);

132
    useEffect(() => {
P
Peter Pan 已提交
133
        ee.on('refresh', mutate);
134
        return () => {
P
Peter Pan 已提交
135
            ee.off('refresh', mutate);
136 137 138
        };
    }, [mutate]);

139 140 141
    return {mutate, ...others};
}

142
export default useRequest;
143
export {useRunningRequest};