Wenn Sie schnell auf Benutzeraktionen reagieren und die neuesten Daten vom Backend abrufen müssen, benötigen Sie möglicherweise einen React Hook, der sequentielle Anfragen unterstützt. Dieser Hook kann frühere Anfragen abbrechen, wenn sie noch laufen, und nur die neuesten Daten zurückgeben. Dies verbessert nicht nur die Leistung, sondern verbessert auch das Benutzererlebnis.
Beginnen wir mit der Erstellung eines einfachen sequentiellen Request-React-Hooks:
import { useCallback, useRef } from 'react'; const buildCancelableFetch =( requestFn: (signal: AbortSignal) => Promise , ) => { const abortController = new AbortController(); return { run: () => new Promise ((resolve, reject) => { if (abortController.signal.aborted) { reject(new Error('CanceledError')); return; } requestFn(abortController.signal).then(resolve, reject); }), cancel: () => { abortController.abort(); }, }; }; function useLatest (value: T) { const ref = useRef(value); ref.current = value; return ref; } export function useSequentialRequest ( requestFn: (signal: AbortSignal) => Promise , ) { const requestFnRef = useLatest(requestFn); const currentRequest = useRef 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]); }
Die Schlüsselidee hier stammt aus dem Artikel „How to Annul Promises in JavaScript.“ Sie können es so verwenden:
import { useSequentialRequest } from './useSequentialRequest'; export function App() { const run = useSequentialRequest((signal: AbortSignal) => fetch('http://localhost:5000', { signal }).then((res) => res.text()), ); return ; }
Wenn Sie auf diese Weise mehrmals schnell auf die Schaltfläche klicken, erhalten Sie nur die Daten der letzten Anfrage und frühere Anfragen werden verworfen.
Wenn wir einen umfassenderen React Hook für sequentielle Anfragen benötigen, gibt es im obigen Code Raum für Verbesserungen. Zum Beispiel:
Wir können die Erstellung eines AbortControllers verschieben, bis er tatsächlich benötigt wird, wodurch unnötige Erstellungskosten reduziert werden.
Wir können Generika verwenden, um jede Art von Anforderungsargumenten zu unterstützen.
Hier ist die aktualisierte Version:
import { useCallback, useRef } from 'react'; function useLatest(value: T) { const ref = useRef(value); ref.current = value; return ref; } export function useSequentialRequest ( requestFn: (signal: AbortSignal, ...args: Args) => Promise, ) { const requestFnRef = useLatest(requestFn); const running = useRef(false); const abortController = useRef (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], ); }
Beachten Sie, dass wir im „finally“-Block prüfen, ob der aktuelle Controller gleich abortController.current ist, um Race-Conditions zu verhindern. Dadurch wird sichergestellt, dass nur die aktive Anforderung den Ausführungsstatus ändern kann.
Umfassendere Nutzung:
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 ( { handleInput(e.target.value); }} />Response Data: {data}> ); }
Sie können es online ausprobieren: Während Sie schnell tippen, werden die vorherigen Anfragen storniert und nur die letzte Antwort angezeigt.
Wenn Sie dies hilfreich fanden, erwägen Sie bitte, meinen Newsletter zu abonnieren für weitere nützliche Artikel und Tools zur Webentwicklung. Danke fürs Lesen!
Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.
Copyright© 2022 湘ICP备2022001581号-3