实现一个 useQuery
hook,用于管理 promise 结果,可用于获取数据。
export default function Component({ param }) {const request = useQuery(async () => {const response = await getDataFromServer(param);return response.data;}, [param]);return (<div>{request.loading && <p>Loading...</p>}{request.error && <p>Error: {request.error.message}</p>}{request.data && <p>Data: {request.data}</p>}</div>);}
fn: () => Promise
: 返回一个 promise 的函数deps: DependencyList
: 依赖项数组,类似于 useEffect
的第二个参数。与 useEffect
不同的是,它默认为 []
该 hook 返回一个对象,该对象具有不同的属性,具体取决于 promise 的状态。
status: 'loading'
: promise 仍在待定中status: 'error'
: promise 被拒绝error: Error
: 导致 promise 被拒绝的错误status: 'success'
: promise 已解决data
: 由 fn
返回的 promise 解决的数据实现一个 useQuery
hook,用于管理 promise 结果,可用于获取数据。
export default function Component({ param }) {const request = useQuery(async () => {const response = await getDataFromServer(param);return response.data;}, [param]);return (<div>{request.loading && <p>Loading...</p>}{request.error && <p>Error: {request.error.message}</p>}{request.data && <p>Data: {request.data}</p>}</div>);}
fn: () => Promise
: 返回一个 promise 的函数deps: DependencyList
: 依赖项数组,类似于 useEffect
的第二个参数。与 useEffect
不同的是,它默认为 []
该 hook 返回一个对象,该对象具有不同的属性,具体取决于 promise 的状态。
status: 'loading'
: promise 仍在待定中status: 'error'
: promise 被拒绝error: Error
: 导致 promise 被拒绝的错误status: 'success'
: promise 已解决data
: 由 fn
返回的 promise 解决的数据useQuery
钩子可以使用 useEffect
实现,以开始 promise 解析并相应地更新状态。
这里的挑战在于意识到 promise 解析与 React 更新是异步的,因此当依赖项在待处理的 promise 解析之前发生更改时,存在竞争条件的可能性。
为了防止这种情况,我们可以使用 ignore
标志来忽略 promise 解析(如果它不再相关,例如依赖项已更改,组件已被卸载)。ignore
在函数的闭包内初始化;每次 useEffect
运行时,该函数都有其自己的 ignore
实例变量,并且可以在 promise 解析时引用它,并且它必须决定是否使用结果。
这种方法在 React 文档中得到了很好的记录。
import { DependencyList, useEffect, useState } from 'react';type AsyncState<T> =| { status: 'loading' }| { status: 'success'; data: T }| { status: 'error'; error: Error };export default function useQuery<T>(fn: () => Promise<T>,deps: DependencyList = [],): AsyncState<T> {const [state, setState] = useState<AsyncState<T>>({status: 'loading',});useEffect(() => {let ignore = false;setState({ status: 'loading' });fn().then((data) => {if (ignore) {return;}setState({ status: 'success', data });}).catch((error) => {if (ignore) {return;}setState({ status: 'error', error });});return () => {ignore = true;};}, deps);return state;}
console.log()
语句将显示在此处。