Sådan bruges Debounce og Throttle til at reagere og abstrakte dem i kroge

Kroge er en strålende tilføjelse til React. De forenkler en masse logik, der tidligere skulle opdeles i forskellige livscyklusser med classkomponenter.

De kræver dog en anden mental model, især for førstegangsbrugere.

Jeg optog også en kort videoserie om denne artikel, som du måske finder nyttige.

Afstem og gashåndtag

Der er masser af blogindlæg skrevet om afvisning og gashåndtag, så jeg dykker ikke ned i, hvordan jeg skriver din egen afvisning og gashåndtag. For kortfattethed, overvej debounceog throttlefra Lodash.

Hvis du har brug for en hurtig genopfriskning, accepterer begge en (tilbagekalds) funktion og en forsinkelse i millisekunder (siger x), og derefter returnerer begge en anden funktion med en særlig funktion:

  • debounce: returnerer en funktion, der kan kaldes et vilkårligt antal gange (muligvis i hurtig rækkefølge), men vil kun påkalde tilbagekald efter at have ventetxms fra det sidste opkald.
  • throttle: returnerer en funktion, der kan kaldes et vilkårligt antal gange (muligvis i hurtig rækkefølge), men kun påkalder tilbagekaldet højst en gang hver xms.

Usecase

Vi har en minimal blogeditor (her er GitHub-repoen), og vi vil gerne gemme blogindlægget i databasen 1 sekund, efter at brugeren holder op med at skrive.

Du kan også henvise til denne kodesandkasse, hvis du ønsker at se den endelige version af koden.

En minimal version af vores editor ser sådan ud:

import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { setValue(event.target.value); }; return (  

Blog

Editor (Client)

{value}

Saved (DB)

{dbValue} ); }

Her saveToDbville der faktisk være et API-opkald til backend. For at holde tingene enkle gemmer jeg det i tilstand og gengiver derefter som dbValue.

Da vi kun ønsker at udføre dette spare driften når brugeren er holdt op med at skrive (efter 1 sekund), skal dette debounced .

Her er startkoden repo og gren.

Oprettelse af en afviste funktion

Først og fremmest har vi brug for en opsagt funktion, der omslutter opkaldet til saveToDb:

import React, { useState } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // highlight-starts const debouncedSave = debounce(() => saveToDb(nextValue), 1000); debouncedSave(); // highlight-ends }; return {/* Same as before */}; } 

Men dette fungerer faktisk ikke, fordi funktionen debouncedSaveoprettes frisk på hvert handleChangeopkald. Dette vil ende med at afvise hvert tastetryk i stedet for at afvise hele inputværdien.

useCallback

useCallbackbruges almindeligvis til ydeevneoptimeringer, når der sendes tilbagekald til underordnede komponenter. Men vi kan bruge dens begrænsning til at huske en tilbagekaldsfunktion for at sikre, at debouncedSavereferencerne har samme afviste funktion på tværs af gengivelser.

Jeg skrev også denne artikel her på freeCodeCamp, hvis du ønsker at forstå det grundlæggende i memoization.

Dette fungerer som forventet:

import React, { useState, useCallback } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // highlight-starts const debouncedSave = useCallback( debounce(nextValue => saveToDb(nextValue), 1000), [], // will be created only once initially ); // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return {/* Same as before */}; } 

useRef

useRefgiver os et ændret objekt, hvis currentegenskab henviser til den beståede startværdi. Hvis vi ikke ændrer det manuelt, forbliver værdien i hele komponentens levetid.

Dette svarer til klasseinstansegenskaber (dvs. definerer metoder og egenskaber til this).

Dette fungerer også som forventet:

import React, { useState, useRef } from 'react'; import debounce from 'lodash.debounce'; function App() { const [value, setValue] = useState(''); const [dbValue, saveToDb] = useState(''); // would be an API call normally // This remains same across renders // highlight-starts const debouncedSave = useRef(debounce(nextValue => saveToDb(nextValue), 1000)) .current; // highlight-ends const handleChange = event => { const { value: nextValue } = event.target; setValue(nextValue); // Even though handleChange is created on each render and executed // it references the same debouncedSave that was created initially debouncedSave(nextValue); }; return {/* Same as before */}; } 

Fortsæt med at læse på min blog for, hvordan man kan abstrakte disse koncepter i brugerdefinerede kroge eller tjekke videoserien.

Du kan også følge mig på Twitter for at holde mig opdateret om mine seneste indlæg. Jeg håber, du fandt dette indlæg nyttigt. :)