@sttot/api-hooks
TypeScript icon, indicating that this package has built-in type declarations

1.2.7 • Public • Published

api-hooks 在 React 中更优雅的定义与使用 Api 请求

在 React 中轻松且规范地定义 API 请求、一键创建钩子函数,包含状态跟踪、请求中断和请求刷新,并方便进行错误处理和批量请求与进度跟踪。


安装

本轮子基于并包含了 @sttot/axios-api,适于 React 使用,如果使用了本轮轮子就不需要额外安装 axios 和 @sttot/axios-api。

pnpm install @sttot/api-hooks

使用

可以使用 apiFactory 用指定 axios 实例创建一个 api 工厂函数:

import axios from 'axios';
import { apiFactory } from '@sttot/api-hooks';

const api = apiFactory(axios.create({}));

如果没有自定义 axios 实例的需求,也可以直接使用默认的 api 工厂函数:

import { api } from '@sttot/api-hooks';

这个 api 函数等价于 @sttot/axios-api 中使用 apiBase 创建的 api 工厂函数,具体用法请参考 @sttot/axios-api,这里只介绍 @sttot/api-hooks 扩展的功能:

创建一个钩子函数

先从最简单的 GET 请求开始,假设已经有如下的 API 定义:

const myApi = api<number, string>(
  id => ({
    method: 'GET',
    url: `https://api.sttot.com/test/${id}`,
  }),
  ({ data }) => data,
);

我们希望在一个 React 组件中使用它:有一个输入 id 的输入框,请求服务器上对应的字符串并显示,可能的话,对错误进行打印、显示加载中、对错误请求进行重试并可以中止请求。可以使用该 Api 创建一个钩子函数:

import { useState } from 'react';
const useInfo = myApi.creatrMemoHook();

export default () => {
  const [id, setId] = useState(0);
  const [result, error, loading, cancel, retry] = useInfo(id, [id]);
  return (
    <div>
      <input
        type="number"
        placeholder="查询 ID"
        onChange={({ target: { value } }) => setId(Number(value) ?? 0)}
      />
      {loading ? <button onClick={() => cancel()}>中止</button> : <></>}
      {error ? (
        <div>
          出错了: {String(error)}
          <button onClick={retry}>重试</button>
        </div>
      ) : (
        <></>
      )}
      <p>{loading ? '加载中...' : `查询结果: ${result ?? ''}`}</p>
    </div>
  );
};

createMemoHook 会创建一个钩子函数,该函数有两个参数,第一个参数接受的是 Api 的参数或者返回 Api 参数的函数;第二个参数和 useEffect 一样,是一个数组,只有数组中的变量改变,才会重新调用请求。

钩子返回一个数组,其中一共有五个对象:

  • 第一个对象是 Api 结果,在请求进行时或出错时是 undefined;
  • 第二个对象是 Api 最终抛出的结果,在请求进行时或者请求成功时是 undefined;
  • 第三个对象是一个布尔值,表示现在请求是否正在进行中;
  • 第四个对象是一个函数,用来中止请求,有一个可选参数用来指定中止原因;
  • 第五个对象是一个函数,用来重新进行请求;

注:不需要用到的对象可以不接收,例如如下写法:

const [result] = useInfo(id, [id]);
const [result, , , , retry] = useInfo(id, [id]);

注:假如有如下代码:

const [result] = useXXX(a, [b]);
useEffect(() => {
  //
}, [result, b]);

应当注意到,当 b 变化时,result 会首先变成 undefined,在请求结束后 result 又会被改变;因此 useEffect 会被调用两次而不是一次。


Reducer 钩子

有时请求 Api 并不需要一个结果,或者调用 Api 的时机并不是某个值被改变了(例如希望在点击按钮时再去查询),此时就需要使用 React 中 Reducer+Dispatch 的思想:

import { useState } from 'react';
const useInfoReducer = myApi.createReducerHook();

export default () => {
  const [id, setId] = useState(0);
  const {
    result,
    error,
    pending,
    idle,
    fullfilled,
    rejected,
    dispatch,
    cancel,
  } = useInfoReducer();
  return (
    <div>
      <input
        type="number"
        placeholder="查询 ID"
        onChange={({ target: { value } }) => setId(Number(value) ?? -1)}
      />
      <button onClick={() => dispatch(id)}>查询</button>
      {loading ? <button onClick={() => cancel()}>中止</button> : <></>}
      {error ? (
        <div>
          出错了: {String(error)}
          <button onClick={() => dispatch(id)}>重试</button>
        </div>
      ) : (
        <></>
      )}
      <p>{pending ? '加载中...' : `查询结果: ${result ?? ''}`}</p>
    </div>
  );
};

result、error、cancel 同上,对不同的部分进行解释:

  • 由于请求在一开始不会自动触发,因此会有四种状态:
    • idle 尚未执行过任何请求;
    • pending 正在执行请求;
    • fullfilled 请求成功;
    • rejected 请求失败;
  • dispatch 是用发起请求的函数,第一个参数是 Api 的参数,第二个是可选参数,Api 请求回调;

除此之外,还有两个钩子,用于做批量请求,具体使用方式类似,请参考代码注释提示:

  • createBatchReducerHook
  • createBatchMemoHook

Readme

Keywords

none

Package Sidebar

Install

npm i @sttot/api-hooks

Weekly Downloads

1

Version

1.2.7

License

none

Unpacked Size

62.5 kB

Total Files

24

Last publish

Collaborators

  • sttot