瀏覽代碼

Merge pull request #282 from qqlcx5/base-useRequest

修复了取消请求时未捕获的 Promise 错误,并确保了 run 函数的返回类型正确。
菲鸽 7 月之前
父節點
當前提交
563b23cf2a
共有 3 個文件被更改,包括 48 次插入12 次删除
  1. 2 2
      src/api/foo.ts
  2. 45 9
      src/hooks/useRequest.ts
  3. 1 1
      src/http/http.ts

+ 2 - 2
src/api/foo.ts

@@ -21,8 +21,8 @@ export interface IFooItem {
 }
 
 /** GET 请求 */
-export function getFooAPI(name: string) {
-  return http.get<IFooItem>('/foo', { name })
+export async function getFooAPI(name: string) {
+  return await http.get<IFooItem>('/foo', { name })
 }
 /** GET 请求;支持 传递 header 的范例 */
 export function getFooAPI2(name: string) {

+ 45 - 9
src/hooks/useRequest.ts

@@ -26,27 +26,62 @@ interface IUseRequestReturn<T, P = undefined> {
  * @returns 返回一个对象{loading, error, data, run},包含请求的加载状态、错误信息、响应数据和手动触发请求的函数。
  */
 export default function useRequest<T, P = undefined>(
-  func: (args?: P) => HttpRequestResult<T>,
+  func: (args?: P) => Promise<T> | Promise<HttpRequestResult<T>> | HttpRequestResult<T> | T,
   options: IUseRequestOptions<T> = { immediate: false },
 ): IUseRequestReturn<T, P> {
   const loading = ref(false)
   const error = ref<boolean | Error>(false)
   const data = ref<T | undefined>(options.initialData) as Ref<T | undefined>
   let requestTask: UniApp.RequestTask | undefined
+  const isCancelled = ref(false)
 
-  const run = async (args?: P) => {
+  const run = async (args?: P): Promise<T | undefined> => {
     loading.value = true
-    const { promise, requestTask: task } = func(args)
-    requestTask = task // Store the requestTask
+    error.value = false
+    isCancelled.value = false
+    let promise: Promise<T | undefined>
+    const result = func(args)
+
+    if (result instanceof Promise) {
+      promise = result.then((res) => {
+        if (res && typeof (res as HttpRequestResult<T>).promise === 'object' && typeof (res as HttpRequestResult<T>).requestTask === 'object') {
+          const { promise: p, requestTask: task } = res as HttpRequestResult<T>
+          requestTask = task
+          if (isCancelled.value) {
+            task.abort()
+            throw new Error('Request cancelled')
+          }
+          return p
+        }
+        if (isCancelled.value) {
+          throw new Error('Request cancelled')
+        }
+        return res as T | undefined
+      }) as Promise<T | undefined>
+    }
+    else if (result && typeof (result as HttpRequestResult<T>).promise === 'object' && typeof (result as HttpRequestResult<T>).requestTask === 'object') {
+      const { promise: p, requestTask: task } = result as HttpRequestResult<T>
+      requestTask = task
+      promise = p
+    }
+    else {
+      promise = Promise.resolve(result as T | undefined)
+    }
+
     return promise
       .then((res) => {
+        if (isCancelled.value) {
+          return
+        }
         data.value = res
-        error.value = false
         return data.value
       })
       .catch((err) => {
-        error.value = err
-        throw err
+        if (!isCancelled.value) {
+          error.value = err
+          throw err
+        }
+        return Promise.resolve(undefined)
       })
       .finally(() => {
         loading.value = false
@@ -54,11 +89,12 @@ export default function useRequest<T, P = undefined>(
   }
 
   const cancel = () => {
+    isCancelled.value = true
     if (requestTask) {
       requestTask.abort()
-      loading.value = false // Reset loading state on cancel
-      error.value = new Error('Request cancelled') // Set a specific error for cancellation
     }
+    loading.value = false
+    error.value = new Error('Request cancelled')
   }
 
   if (options.immediate) {

+ 1 - 1
src/http/http.ts

@@ -24,7 +24,7 @@ export function http<T>(options: CustomRequestOptions) {
         // 状态码 2xx,参考 axios 的设计
         if (res.statusCode >= 200 && res.statusCode < 300) {
           // 2.1  处理业务逻辑错误
-          const { code, message, msg, data } = res.data as IResponse<T>
+          const { code = 0, message = '', data = null } = res.data as IResponse<T>
           // 0和200当做成功都很普遍,这里直接兼容两者,见 ResultEnum
           if (code !== ResultEnum.Success0 && code !== ResultEnum.Success200) {
             throw new Error(`请求错误[${code}]:${message || msg}`)