npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@umijs/use-api

v0.3.0

Published

React Hooks for fetching, caching and updating asynchronous data

Downloads

11

Readme

useAPI

Production-ready React Hooks library for manage asynchronous data.

NPM version NPM downloads

特性

  • 自动请求/手动请求
  • SWR(stale-while-revalidate)
  • 缓存/预加载
  • 屏幕聚焦重新请求
  • 轮询
  • 防抖
  • 节流
  • 并行请求
  • loading delay
  • 分页
  • 加载更多,数据恢复 + 滚动位置恢复
  • [ ] 错误重试
  • [ ] 请求超时管理
  • [ ] suspense
  • ......

在线体验

Edit

快速开始

安装

$ npm i @umijs/use-api --save
# or 
$ yarn add @umijs/use-api

使用

//service 为异步函数。
const {data, error, loading} = useAPI(service);
import React from 'react';
import useAPI from '@umijs/use-api';

export default () => {
  const { data, error, loading } = useAPI(getUserInfo)

  if (error) return <div>failed to load</div>
  if (loading) return <div>loading...</div>
  return <div>hello {data.username}!</div>
}

在这个例子中, useAPI 接收了一个异步函数 getUserInfo ,在组件初次加载时,自动触发该函数执行。同时 useAPI 会自动管理异步请求的 loading , data , error 等状态。

文档

默认请求

代码示例

快速开始 例子一样, useAPI 在组件初始化时会默认执行 service。

手动触发

代码示例

通过设置 options.manual = true , 则需要手动调用 run 时才会触发执行。

const { loading, run } = useAPI(changeUsername, {
  manual: true,
});

<button onClick={() => run('new name')}>
    {loading ? 'Editting...' : 'Edit'}
</button>

突变

代码示例

你可以通过 mutate ,直接修改 datamutate 函数参数可以为 newData(data)=> newData

const { data, mutate } = useAPI(getUserInfo);

<button onClick={() => mutate('new name')}>
    Edit
</button>

轮询

代码示例

通过设置 pollingInterval ,进入轮询模式,定时触发函数执行。同时可以通过设置 pollingWhenHidden = false ,在屏幕不可见时,暂时暂停定时任务。

  • 你可以通过 run / cancel 来 开启/停止 轮询。
  • manual=true 时,需要第一次执行 run 后,才开始轮询。
const { data, loading } = useAPI(getUserInfo, {
  pollingInterval: 1000,
  pollingWhenHidden: false
});

防抖

代码示例

通过设置 debounceInterval ,则进入防抖模式。此时如果频繁触发 run ,则会以防抖策略进行请求。

const { data, loading, run } = useAPI(getUserInfo, {
  debounceInterval: 500
});

节流

代码示例

通过设置 throttleInterval ,则进入节流模式。此时如果频繁触发 run ,则会以节流策略进行请求。

const { data, loading, run } = useAPI(getUserInfo, {
  throttleInterval: 500
});

缓存 & SWR

代码示例

如果设置了 cacheKey , useAPI 会将当前请求结束数据缓存起来。下次组件初始化时,如果有缓存数据,我们会优先返回缓存数据,然后在背后发送新请求,也就是 SWR 的能力。

const { data, loading, run } = useAPI(getInfo, {
  cachekey: 'getInfoKey'
});

1

预加载

代码示例

同一个 cacheKey 的请求,是全局共享的,也就是你可以提前加载数据。利用该特性,可以很方便的实现预加载。你可以在线上例子中体验一下。

屏幕聚焦重新请求

代码示例

如果你设置了 refreshOnWindowFocus = true ,则在浏览器窗口 refoucrevisible 时,会重新发起请求。

你可以通过设置 focusTimespan 来设置请求间隔,默认为 5000ms

const { data, loading } = useAPI(getUserInfo, {
  refreshOnWindowFocus: true,
  focusTimespan: 5000
});

并行请求

代码示例1 代码示例2

通过 fetchKey ,可以将请求进行分类,每一类的请求都有独立的状态,你可以在 fetches 中找到所有的请求。

const { run, fetches } = useAPI(disableUser, {
  manual: true,
  fetchKey: (id) => id,
});

2

3

Loading Delay

代码示例

通过设置 loadingDelay ,可以延迟 loading 变成 true 的时间,有效防止请求抖动。

const withLoadingDelayAction = useAPI(getCurrentTime, {
    loadingDelay: 200
});

4

refreshDeps

代码示例

当某些 state 变化时,我们需要重新执行异步请求,一般我们会这样写代码:

const [userId, setUserId] = useState('1');
const { data, run, loading } = useAPI(getUserSchool, { manual: true });
useEffect(() => {
  run();
}, [userId]);

refreshDeps 是一个语法糖,让你更方便的实现上面的功能。当 refreshDeps 变化时,我们会重新执行异步请求。

const [userId, setUserId] = useState('1');
const { data, run, loading } = useAPI(() => {
  return getUserSchool()
}, {
  refreshDeps: [userId]
});

基础 API

const {
  data,
  error,
  loading,
  run,
  params,
  cancel,
  refresh,
  mutate,
  fetches,
} = useAPI(service, {
  manual,
  initialData,
  refreshDeps,
  onSuccess,
  onError,
  formatResult,
  cacheKey,
  loadingDelay,
  defaultParams,
  pollingInterval,
  pollingWhenHidden,
  fetchKey,
  refreshOnWindowFocus,
  focusTimespan,
  debounceInterval,
  throttleInterval,
}); 

返回

  • data: undefined | any

  • service 返回的数据,默认为 undefined

    • 如果有 formatResult, 则该数据为被格式化后的数据。
  • error: undefined | Error

    • service 抛出的异常,默认为 undefined
  • loading: boolean

    • service 是否正在执行。
  • run: (...args: any[]) => Promise

    • 手动触发 service 执行,参数会传递给 service。
  • params: any[]

    • 当次执行的 service 的参数数组。比如你触发了 run(1, 2, 3),则 params 等于 [1, 2, 3]
  • cancel: () => void

    • 取消当前请求。
    • 如果有轮询,停止。
  • refresh: () => void

    • 使用上一次的 params,重新执行 service。
  • mutate: data | (data)=>newData

    • 直接修改 data。
  • fetches: {[key:string]: {loading,data,error,params,cancel,refresh,mutate,run}}

    • 默认情况下,新请求会覆盖旧请求。如果设置了 fetchKey,则可以实现多个请求并行,fetches 存储了多个请求的状态。
    • 外层的状态为最新触发的 fetches 数据。

参数

所有的 Options 均是可选的。

  • manual: boolean

    • 默认 false。 即在初始化时自动执行 service。
    • 如果设置为 true,则需要手动调用 run 触发执行。
  • initialData: any

    • 默认的 data
  • refreshDeps: any[]

    • manual = false 时,refreshDeps 变化,会触发 service 重新执行。
  • formatResult: (response: any) => any

    • 格式化请求结果。
  • onSuccess: (data:any, params: any[]) => void

    • service resolve 时触发,参数为 dataparams
    • 如果有 formmatResult ,则 data 为格式化后数据。
  • onError: (error: Error, params: any[]) => void

    • service 报错时触发,参数为 errorparams
  • fetchKey: (...params: any[]) => string

    • 根据 params,获取当前请求的 key,设置之后,我们会在 fetches 中同时维护不同 key 值的请求状态。
  • cacheKey: string

    • 请求唯一标识。如果设置了 cacheKey,我们会启用缓存机制。
    • 我们会缓存每次请求的 data , error , params , loading
    • 在缓存机制下,同样的请求我们会先返回缓存中的数据,同时会在背后发送新的请求,待新数据返回后,重新触发数据更新。
  • defaultParams: any[]

    • 如果 manual=false ,自动执行 run 的时候,默认带上的参数。
  • loadingDelay: number

    • 设置显示 loading 的延迟时间,避免闪烁。
  • pollingInterval: number

    • 轮询间隔,单位为毫秒。设置后,将进入轮询模式,定时触发 run
  • pollingWhenHidden: boolean

    • 在页面隐藏时,是否继续轮询。默认为 true,即不会停止轮询。
    • 如果设置为 false , 在页面隐藏时会暂时停止轮询,页面重新显示时继续上次轮询。
  • refreshOnWindowFocus: boolean

    • 在屏幕重新获取焦点或重新显示时,是否重新发起请求。默认为 false,即不会重新发起请求。
    • 如果设置为 true,在屏幕重新聚焦或重新显示时,会重新发起请求。
  • focusTimespan: number

    • 屏幕重新聚焦,如果每次都重新发起请求,不是很好,我们需要有一个时间间隔,在当前时间间隔内,不会重新发起请求。默认为 5000ms
    • 需要配置 refreshOnWindowFocus 使用。
  • debounceInterval: number

    • 防抖间隔, 单位为毫秒,设置后,请求进入防抖模式。
  • throttleInterval:number

    • 节流间隔, 单位为毫秒,设置后,请求进入节流模式。

扩展用法

基于基础的 useAPI,我们可以进一步封装,实现更高级的定制需求。当前 useAPI 内置了 集成请求库分页加载更多 三种场景。你可以参考代码,实现自己的封装。参考 useRequestusePaginateduseLoadMore 的实现。

集成请求库

如果 service 是 stringobject(...args)=> string|object, 我们会自动使用 um-request 来发送网络请求。umi-request 是类似 axios、fetch 的请求库。

代码示例1 代码示例2

// 用法 1
const { data, error, loading } = useAPI('/api/userInfo');

// 用法 2
const { data, error, loading } = useAPI({
  url: '/api/changeUsername',
  method: 'post',
});

// 用法 3
const { data, error, loading } = useAPI((userId)=> `/api/userInfo/${userId}`);

// 用法4
const { loading, run } = useAPI((username) => ({
  url: '/api/changeUsername',
  method: 'post',
  data: { username },
}), {
  manual: true,
});

Q:如果我要使用 axiosfetch 咋办?如何设置 umi-request 的全局配置? A:你可以通过设置 requestMehod 即可。参考 示例代码。当然,你可以通过 UseAPIProvider 全局设置请求方法哦。

API
const {...} = useAPI<R>(
  service: string | object | ((...args:any) => string | object), 
  {
    ...,
    requestMehod?: (service) => Promise
  })
service

如果 service 是 stringobject(...args)=> string|object,则自动使用 umi-request 来发送请求。

参数
  • requestMehod:(service: string|object)) => Promise

    • 异步请求方法,参数为 service 或 service 返回的参数。如果设置该参数,则默认使用该函数发送网络请求。

分页

通过设置 options.paginated = true , useAPI 将以分页模式运行,此时会有以下特性:

  • useAPI 会自动管理分页 current , pageSize 。service 的第一个参数为 {current, pageSize}
  • service 返回的数据结构必须为 {list: Item[], total: number} ,如果不满足,可以通过 options.formatResult 转换一次。
  • 会额外返回 pagination 字段,包含所有分页信息,及操作分页的函数。
  • refreshDeps 变化,会重置 current 到第一页,并重新发起请求,一般你可以把 pagination 依赖的条件放这里。
示例 1

代码示例

普通的分页场景,我们会自动管理 currentpageSize

const { data, loading, pagination } = useAPI(
  ({ current, pageSize }) => getUserList({ current, pageSize }),
  {
    paginated: true,
  }
);
示例 2

代码示例

由于 antd Table 使用比较广泛,我们特别支持了 antd Table 需要的分页格式,及 sorterfilters 等。你可以通过 result.tablePropsresult.filtersresult.sorter 访问到这些属性。

const { tableProps, sorter, filters } = useAPI((params) => {
  return getUserList(params);
}, {
  paginated: true
});

return (<Table columns={columns} rowKey="id" {...tableProps} />);
示例 3

代码示例

cacheKey 场景下, run 的参数 params 是可以缓存的,利用这个特点,我们可以实现 pagination 相关条件的缓存。

一个复杂的带条件,带缓存的 pagination 例子。

5

API
const {
  ...,
  pagination: {
    current: number;
    pageSize: number;
    total: number;
    totalPage: number;
    onChange: (current: number, pageSize: number) => void;
    changeCurrent: (current: number) => void;
    changePageSize: (pageSize: number) => void;
  };
  tableProps: {
    dataSource: Item[];
    loading: boolean;
    onChange: (
      pagination: PaginationConfig,
      filters?: Record<keyof Item, string[]>,
      sorter?: SorterResult<Item>,
    ) => void;
    pagination: {
      current: number;
      pageSize: number;
      total: number;
    };
  };

  sorter?: SorterResult<Item>;
  filters?: Record<keyof Item, string[]>;
} = useAPI(service, {
  ...,
  paginated,
  defaultPageSize,
  refreshDeps,
}); 
返回
  • pagination

    • 分页数据及操作分页的方法。
  • tableProps

    • 适配 antd Table 组件的数据结构,可以直接用在 Table 组件上。
  • sorter

    • antd Table sorter。
  • filters

    • antd Table filters。
参数
  • paginated: boolean

    • 是否开启分页模式,默认为 false
    • 如果设置为 true,则开启分页模式。在分页模式下,service 的第一个参数为 {curret, pageSize, sorter, filters}
    • 响应结果或 formatResult 结果必须为 {list: Item[], total: number}
  • refreshDeps

    • 分页模式下, refreshDeps 变化,会重置 current 到第一页,并重新发起请求,一般你可以把依赖的条件放这里。

加载更多

代码示例

通过设置 options.loadMore = true , useAPI 将以 loadMore 模式运行,此时会有以下特性:

  • service 返回的数据结构必须包含 {list: Item[], nextId: string|undefined} ,如果不满足,可以通过 options.formatResult 转换一次。
  • useAPI 会自动管理列表数据 。service 的第一个参数为 nextId
  • 会额外返回 result.loadingMoreresult.loadMore
  • refreshDeps 变化,会清空当前数据,并重新发起请求,一般你可以把 loadMore 依赖的条件放这里。
const { data, run, loadMore, loading, loadingMore } = useAPI((nextId) => {
  return getUserList(nextId);
}, {
  loadMore: true
});

6

API
const {
  ...,
  loadMore,
  loadingMore,
} = useAPI(service, {
  ...,
  loadMore,
  refreshDeps,
}); 
返回
  • loadMore: ()=>void

    • 触发加载更多
  • loadingMore: boolean

    • 是否正在加载更多
参数
  • loadMore: boolean

    • 是否开启加载更多模式,默认为 false
    • 如果设置为 true,则开启加载更多模式。在该模式下,service 的第一个参数为 nextId
    • 响应结果或 formatResult 结果必须为 {list: Item[], nextId: string|undefined}
  • refreshDeps

    • 加载更多模式下, refreshDeps 变化,会清空当前数据,并重新发起请求,一般你可以把依赖的条件放这里。

全局配置

UseAPIProvider

你可以通过 UseAPIProvider 在项目的最外层设置全局 options。

import {UseAPIProvider} from '@umijs/use-api';

export function ({children})=>{
  return (
    <UseAPIProvider value={{
      refreshOnWindowFocus: true,
      requestMethod: (param)=> axios(param),
      ...
    }}>
      {children}
    </UseAPIProvider>
  )
}

致谢

License

MIT