Agent 3 — rn-update: - downloadPlugin/downloadApk 新增 onProgress 进度回调 - checkAppUpdate/checkPluginUpdate 版本缓存(30分钟 TTL) - 新增 UpdateDownloadProgress 类型导出 Agent 3 — rn-xwebview: - XWebViewBridge 补全标准 JSBridge handler - getDeviceInfo/getToken/getUserInfo/openNativePage/closeWebView/showToast Agent 4 — rn-log v0.1.0: - XLog 主入口:event/captureError/warn/info/startCapture - LogQueue:AsyncStorage 本地队列 + 批量上报 - ErrorCapture:JS global error + unhandledRejection - FunnelTracker:漏斗分析 - fingerprint:SHA-256 指纹去重 - HttpInterceptor:rn-common HTTP 错误自动上报 - NativeLogReporter:TurboModule spec
129 行
3.3 KiB
TypeScript
129 行
3.3 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import type { AxiosRequestConfig } from 'axios'
|
|
import type { RequestError } from './errors'
|
|
import type { RequestOptions } from './useRequest'
|
|
import { z } from 'zod'
|
|
|
|
import { useApi } from './useApi'
|
|
|
|
type List<T> = {
|
|
records: T[]
|
|
}
|
|
|
|
type Root<T> = T[]
|
|
|
|
interface PageOptions extends RequestOptions {
|
|
pageSize?: number
|
|
path?: 'list' | 'root'
|
|
pagination?: 'cursor' | 'offset'
|
|
}
|
|
|
|
export const usePageApi = <
|
|
S extends z.ZodTypeAny,
|
|
T extends z.infer<S> = z.infer<S>,
|
|
P extends List<T> | Root<T> = List<T>,
|
|
D = Record<string, unknown>,
|
|
>(
|
|
url: string,
|
|
method: 'GET' | 'POSTJSON' | 'POSTFORM',
|
|
params?: D,
|
|
validationSchema?: S,
|
|
options?: PageOptions,
|
|
config?: AxiosRequestConfig<D>,
|
|
): {
|
|
response?: T[]
|
|
error?: RequestError<unknown>
|
|
loading: boolean
|
|
fetch: React.Dispatch<React.SetStateAction<'reload' | 'loadmore'>>
|
|
cancel: () => void
|
|
} => {
|
|
const [data, setData] = useState<T[] | undefined>(undefined)
|
|
const [status, setStatus] = useState<'loaded' | 'reload' | 'loadmore'>('loaded')
|
|
|
|
const listSchema: z.ZodSchema<List<T>> = z.object({
|
|
records: z.array(validationSchema ?? z.any()),
|
|
})
|
|
const rootSchema: z.ZodSchema<Root<T>> = z.array(validationSchema ?? z.any())
|
|
|
|
const { error, loading, fetchAsync, cancel } = useApi<
|
|
typeof listSchema | typeof rootSchema,
|
|
P
|
|
>(
|
|
url,
|
|
method,
|
|
options?.pagination === 'offset'
|
|
? {
|
|
...params,
|
|
current:
|
|
status === 'loadmore'
|
|
? Math.ceil((data ?? []).length / (options?.pageSize ?? 10)) + 1
|
|
: 1,
|
|
size: options?.pageSize ?? 10,
|
|
}
|
|
: {
|
|
...params,
|
|
startNum: status === 'loadmore' ? (data ?? []).length : 0,
|
|
endNum:
|
|
status === 'loadmore'
|
|
? (data ?? []).length + (options?.pageSize ?? 10) - 1
|
|
: (options?.pageSize ?? 10) - 1,
|
|
},
|
|
options?.path === 'root' ? rootSchema : listSchema,
|
|
options,
|
|
config,
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (
|
|
status === 'loaded' ||
|
|
(status === 'loadmore' &&
|
|
((data ?? []).length === 0 ||
|
|
(data ?? []).length % (options?.pageSize ?? 10) !== 0))
|
|
) {
|
|
return
|
|
}
|
|
|
|
fetchAsync()
|
|
.then(result => {
|
|
if (status === 'reload') {
|
|
switch (options?.path) {
|
|
case 'root':
|
|
setData(result as Root<T>)
|
|
break
|
|
default:
|
|
setData((result as List<T>).records)
|
|
break
|
|
}
|
|
setStatus('loaded')
|
|
return
|
|
}
|
|
|
|
switch (options?.path) {
|
|
case 'root':
|
|
setData(previous => [...(previous ?? []), ...(result as Root<T>)])
|
|
break
|
|
default:
|
|
setData(previous => [
|
|
...(previous ?? []),
|
|
...(result as List<T>).records,
|
|
])
|
|
break
|
|
}
|
|
setStatus('loaded')
|
|
})
|
|
.catch(() => {
|
|
setStatus('loaded')
|
|
})
|
|
}, [data, fetchAsync, options?.pageSize, options?.path, status])
|
|
|
|
return {
|
|
response: data,
|
|
error: error as RequestError<unknown>,
|
|
loading,
|
|
fetch: setStatus as React.Dispatch<React.SetStateAction<'reload' | 'loadmore'>>,
|
|
cancel,
|
|
}
|
|
}
|
|
|
|
export type { AxiosRequestConfig, PageOptions }
|