「✍ React Hooks」丝滑的useFetch

739 阅读1分钟

base type

export interface IBaseRes<R> {
  result: number
  res_info: string
  result_rows: R
}

api function

import { IBaseRes } from './typing'

export interface IReqProps {
  uid: string
}

export interface IResProps {
  uid: string
  name: string
  age: number /*  */
}

type IReqFun<T, U> = (params?: T) => Promise<IBaseRes<U>>


export const queryUserByUid: IReqFun<IReqProps, IResProps> = (params) =>
  new Promise((resolve) =>
    setTimeout((=> {
      resolve({
        result: 0,
        res_info: 'ok',
        result_rows: {
          uid: params.uid,
          name: 'xiaoming',
          age: 20,
        },
      })
    }, 2000)
  )

export default {}

注:api function若只用于useFetch,可不写类型,在useFetch时传入对应类型即可。但若可能直接调用,则需要加上类型

useFetch

/* eslint-disable no-alert */
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-unused-vars */
import { useCallback, useState } from 'react'

import { IBaseRes } from './typing'

type IStatus = 'loading' | 'success' | 'fail' | 'standby'

/**
 *  <T : 接口入参,  U: 接口出参>
 * @param IReqFun
 * @returns
 */
const useFetch = <T, U>(props: {
  excuteFn:
  | ((params?: T) => Promise<IBaseRes<U>>)
  | ((params?: T) => Promise<any>)
  | ((params?: any) => Promise<IBaseRes<U>>)
  | ((params: any) => Promise<any>)
}): {
  data: U
  status: IStatus
  excute: (params?: T) => void
} => {
  const { excuteFn } = props
  const [data, setData] = useState({} as U)
  const [status, setStatus] = useState<IStatus>('standby')
  const excute = useCallback(
    async (params) => {
      setStatus('loading')
      try {
        let res = await excuteFn(params)
        const { result, res_info, result_rows } = res
        if (result !== 0) {
          setStatus('fail')
          return
        }
        setData(result_rows)
        setStatus('success')
      } catch (e) {
        setStatus('fail')
      }
    },
    [excuteFn]
  )
  return {
    excute,
    status,
    data,
  }
}
export default useFetch

demo

import React, { useEffect } from 'react'
import { queryUserByUid, IReqProps, IResProps } from './api'
import useFetch from './useFetch'

const Demo: React.FC = () => {
  const { data, status, excute } = useFetch<IReqProps, IResProps>({
    excuteFn: queryUserByUid,
  })
  useEffect(() => {
    excute({
      uid: '1',
    })
  }, [excute])

  return (
    <div>
      {status === 'success' && (
        <>
          <span>{data.uid}</span>
          <span>{data.name}</span>
          <span>{data.age}</span>
        </>
      )}
    </div>
  )
}

export default Demo