Cârlige sunt o completare strălucitoare la React. Ele simplifică o mulțime de logici care anterior trebuiau împărțite în diferite cicluri de viață class componente.

Cu toate acestea, necesită o diferit model mental, în special pentru primii.

Am înregistrat și un scurtmetraj seriale video pe acest articol pe care îl puteți găsi de ajutor.

Debounce și accelerație

Există o mulțime de postări pe blog scrise despre debounce și accelerație, așa că nu mă voi scufunda în cum să scriu propriile dvs. debounce și accelerație. Pentru scurtă durată, luați în considerare debounce și throttle din Lodash.

Dacă aveți nevoie de o reîmprospătare rapidă, ambele acceptă o funcție (callback) și a întârziere în milisecunde (să zicem x) și apoi ambii returnează o altă funcție cu un anumit comportament special:

  • debounce: returnează o funcție care poate fi apelată de câte ori (posibil în succesiuni rapide), dar va invoca doar apelul invers după așteptare pentru x ms de la ultimul apel.
  • throttle: returnează o funcție care poate fi apelată de câte ori (posibil într-o succesiune rapidă), dar va invoca apelul de apel cel mult o singura data fiecare x Domnișoară.

Utilizare caz

Avem un editor de blog minim (aici este Repo GitHub) și am dori să salvăm postarea pe blog în baza de date la o secundă după ce utilizatorul încetează să scrie.

Vă puteți referi și la acest Codesandbox dacă doriți să vedeți versiunea finală a codului.

O versiune minimă a editorului nostru arată astfel:

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 (
		<main>
			<h1>Blog</h1>
			<textarea value={value} onChange={handleChange} rows={5} cols={50} />
			<section className="panels">
				<div>
					<h2>Editor (Client)</h2>
					{value}
				</div>
				<div>
					<h2>Saved (DB)</h2>
					{dbValue}
				</div>
			</section>
		</main>
	);
}

Aici, saveToDb ar fi de fapt un apel API către backend. Pentru a simplifica lucrurile, îl salvez în stare și apoi redau ca dbValue.

Deoarece vrem să efectuăm această operațiune de salvare numai după ce utilizatorul a încetat să scrie (după 1 secundă), aceasta ar trebui să fie dezbătut.

Iată repoarea și ramificarea codului de pornire.

Crearea unei funcții dezbatute

Mai întâi de toate, avem nevoie de o funcție dezactivată care să încheie apelul către 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 <main>{/* Same as before */}</main>;
}

Dar acest lucru nu funcționează de fapt, deoarece funcția debouncedSave este creat proaspăt pe fiecare handleChange apel. Acest lucru va sfârși prin a respinge fiecare apăsare de tastă, mai degrabă decât pentru a respinge întreaga valoare de intrare.

useCallback

useCallback este utilizat în mod obișnuit pentru optimizări de performanță la trecerea apelurilor către componentele copil. Dar putem folosi constrângerea sa de a memora o funcție de apel invers pentru a asigura debouncedSave face referire la aceeași funcție dezmințită între randări.

De asemenea, am scris acest articol aici pe Routech dacă doriți să înțelegeți noțiunile de bază ale memoizării.

Acest lucru funcționează conform așteptărilor:

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 <main>{/* Same as before */}</main>;
}

useRef

useRef ne dă un obiect mutabil al cărui current proprietatea se referă la valoarea inițială trecută. Dacă nu o schimbăm manual, valoarea va persista pe toată durata de viață a componentei.

Acest lucru este similar cu proprietățile instanței de clasă (adică definirea metodelor și proprietăților pe this).

De asemenea, acest lucru funcționează conform așteptărilor:

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 <main>{/* Same as before */}</main>;
}

Continuați să citiți mai departe blogul meu pentru cum să abstractizați aceste concepte în cârlige personalizate sau să verificați seriale video.

Poți să mă urmărești și pe mine Stare de nervozitate să fiu la curent cu ultimele mele postări. Sper că ți s-a părut utilă această postare. 🙂