问题
我创建了一个自定义的 React 钩子,其中包含fetch
一个AbortSignal
和一个 loading state
。(我完全了解我可以使用的大量库,但这是针对企业应用程序的,这是此用例的最佳方法。)
钩子按预期工作。它允许我在需要时调用包装的 fetch(甚至传递给React-Query
),我可以按需调用中止调用,并根据加载状态更新 UI。
我可以很容易地测试钩子的返回值、被包装的 fetch 的调用、中止信号的功能;但是,我在loading
仅使用 jest 测试状态时遇到了很大的麻烦,并且react-hooks-testing-library
. Component
如果可以避免,我不想为此测试创建一个。
我希望能够调用包装的 fetch,并将加载状态视为 true,然后在解析后,将加载状态视为 false。目前,加载状态始终返回为 false。
use-wrapped-fetch.ts
对于这个钩子的内部状态,我已经尝试过useRef
, useState
, useReducer
,并且我在测试任何一种方式时都遇到了同样的问题。我也useCallback
完全删除了相同的结果。
function useWrappedFetch<
RequestBody = unknown,
ResponseData = unknown,
>(): UseWrappedFetchState<RequestBody, ResponseData> {
const abortController = React.useRef<AbortController | undefined>(undefined);
const isFetching = React.useRef<boolean>(false);
const wrappedFetch = React.useCallback(async ({
init,
config,
}: WrappedFetchInit<RequestBody>): Promise<ResponseData> => {
abortController.current = new AbortController();
isFetching.current = true;
const method: Lowercase<keyof CoreFetch> = coreFetchMethod(config.method ?? 'GET');
try {
return fetch[method]<ResponseData>(init, {
...config,
timeout: config.timeout ?? fetchTimeout,
signal: abortController.current.signal,
});
} finally {
isFetching.current = false;
}
}, []);
return {
abortController: abortController.current,
wrappedFetch,
isFetching: isFetching.current,
};
}
use-wrapped-fetch.spec.ts
测试用于msw
在服务工作者上启动模拟服务器。下面的测试在第一次期望时失败(返回false
而不是期望true
)。
it('sets isLoading to true on api call, then sets to false on resolve', async () => {
// Given
const config = deleteRequestConfig({});
const init = 'https://internal.local/delete-short-delay';
// When
const { result, waitForNextUpdate } = renderHook(useWrappedFetch);
act(() => {
result.current.wrappedFetch({ init, config });
});
expect(result.current.isFetching).toBe(true);
await waitForNextUpdate();
expect(result.current.isFetching).toBe(false);
});