사용자 작업에 빠르게 응답하고 백엔드에서 최신 데이터를 가져와야 하는 경우 순차적 요청을 지원하는 React Hook이 필요할 수 있습니다. 이 후크는 이전 요청이 아직 진행 중인 경우 취소하고 가장 최근 데이터만 반환할 수 있습니다. 이는 성능을 향상시킬 뿐만 아니라 사용자 경험도 향상시킵니다.
간단한 순차 요청 React 후크를 구축하는 것부터 시작해 보겠습니다.
import { useCallback, useRef } from 'react'; const buildCancelableFetch = <T>( requestFn: (signal: AbortSignal) => Promise<T>, ) => { const abortController = new AbortController(); return { run: () => new Promise<T>((resolve, reject) => { if (abortController.signal.aborted) { reject(new Error('CanceledError')); return; } requestFn(abortController.signal).then(resolve, reject); }), cancel: () => { abortController.abort(); }, }; }; function useLatest<T>(value: T) { const ref = useRef(value); ref.current = value; return ref; } export function useSequentialRequest<T>( requestFn: (signal: AbortSignal) => Promise<T>, ) { const requestFnRef = useLatest(requestFn); const currentRequest = useRef<{ cancel: () => void } | null>(null); return useCallback(async () => { if (currentRequest.current) { currentRequest.current.cancel(); } const { run, cancel } = buildCancelableFetch(requestFnRef.current); currentRequest.current = { cancel }; return run().finally(() => { if (currentRequest.current?.cancel === cancel) { currentRequest.current = null; } }); }, [requestFnRef]); }
여기서 핵심 아이디어는 'JavaScript에서 약속을 취소하는 방법' 기사에서 나왔습니다. 다음과 같이 사용할 수 있습니다.
import { useSequentialRequest } from './useSequentialRequest'; export function App() { const run = useSequentialRequest((signal: AbortSignal) => fetch('http://localhost:5000', { signal }).then((res) => res.text()), ); return <button onClick={run}>Run</button>; }
이렇게 하면 버튼을 여러 번 빠르게 클릭하면 최근 요청의 데이터만 가져오고 이전 요청은 삭제됩니다.
보다 포괄적인 순차 요청 React Hook이 필요한 경우 위 코드를 개선할 여지가 있습니다. 예:
실제로 필요할 때까지 AbortController 생성을 연기하여 불필요한 생성 비용을 줄일 수 있습니다.
제네릭을 사용하여 모든 유형의 요청 인수를 지원할 수 있습니다.
업데이트된 버전은 다음과 같습니다.
import { useCallback, useRef } from 'react'; function useLatest<T>(value: T) { const ref = useRef(value); ref.current = value; return ref; } export function useSequentialRequest<Args extends unknown[], Data>( requestFn: (signal: AbortSignal, ...args: Args) => Promise<Data>, ) { const requestFnRef = useLatest(requestFn); const running = useRef(false); const abortController = useRef<AbortController | null>(null); return useCallback( async (...args: Args) => { if (running.current) { abortController.current?.abort(); abortController.current = null; } running.current = true; const controller = abortController.current ?? new AbortController(); abortController.current = controller; return requestFnRef.current(controller.signal, ...args).finally(() => { if (controller === abortController.current) { running.current = false; } }); }, [requestFnRef], ); }
finally 블록에서는 경쟁 조건을 방지하기 위해 현재 컨트롤러가 abortController.current와 같은지 확인합니다. 이렇게 하면 활성 요청만 실행 상태를 수정할 수 있습니다.
더 포괄적인 사용법:
import { useState } from 'react'; import { useSequentialRequest } from './useSequentialRequest'; export default function Home() { const [data, setData] = useState(''); const run = useSequentialRequest(async (signal: AbortSignal, query: string) => fetch(`/api/hello?query=${query}`, { signal }).then((res) => res.text()), ); const handleInput = async (queryStr: string) => { try { const res = await run(queryStr); setData(res); } catch { // ignore errors } }; return ( <> <input placeholder="Please input" onChange={(e) => { handleInput(e.target.value); }} /> <div>Response Data: {data}</div> </> ); }
온라인으로 시도해 볼 수 있습니다. 빠르게 입력하면 이전 요청이 취소되고 최신 응답만 표시됩니다.
이 내용이 도움이 되었다면 웹 개발에 대한 더 유용한 기사와 도구를 보려면 제 뉴스레터를 구독하세요 . 읽어주셔서 감사합니다!
위 내용은 순차적 요청을 처리하는 React Hook을 구축하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!