Ontgrendel de kracht van useRef in React. Verken diverse use cases, waaronder directe DOM-toegang, het behouden van muteerbare waarden en het optimaliseren van het gedrag van functionele componenten.
React useRef: Meester in het Opslaan van Muteerbare Waarden
useRef is een krachtige hook in React die een manier biedt om waarden tussen renders te behouden zonder nieuwe renders te veroorzaken wanneer die waarden veranderen. Het wordt vaak geassocieerd met directe toegang tot DOM-elementen, maar de mogelijkheden reiken veel verder. Deze uitgebreide gids duikt in de diverse use cases van useRef, zodat u efficiëntere en beter onderhoudbare React-code kunt schrijven.
useRef Begrijpen: Meer Dan Alleen DOM-toegang
In de kern retourneert useRef een muteerbaar ref-object waarvan de .current eigenschap wordt geïnitialiseerd met het doorgegeven argument (initialValue). Het geretourneerde object blijft bestaan gedurende de volledige levensduur van de component. Cruciaal is dat het aanpassen van de .current eigenschap geen nieuwe render activeert. Dit is het belangrijkste verschil tussen useRef en useState.
Hoewel toegang tot DOM-elementen een veelvoorkomende use case is, blinkt useRef uit in het beheren van elke muteerbare waarde die geen nieuwe render hoeft te veroorzaken bij een update. Dit maakt het van onschatbare waarde voor taken zoals:
- Het opslaan van vorige prop- of state-waarden.
- Het bijhouden van tellers of timers.
- Het volgen van de focus-status zonder nieuwe renders te veroorzaken.
- Het opslaan van elke muteerbare waarde die over renders heen moet blijven bestaan.
Basisgebruik: Toegang tot DOM-elementen
De bekendste use case is directe toegang tot DOM-elementen. Dit is handig voor scenario's waarin u imperatief moet interageren met een DOM-node, zoals het focussen van een invoerveld, het meten van de afmetingen ervan, of het activeren van animaties.
Voorbeeld: Een Invoerveld Focussen
Hier ziet u hoe u useRef kunt gebruiken om een invoerveld te focussen wanneer een component wordt gemount:
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const inputRef = useRef(null);
useEffect(() => {
// Focus het invoerveld bij het mounten
if (inputRef.current) {
inputRef.current.focus();
}
}, []); // Lege dependency array zorgt ervoor dat dit slechts één keer wordt uitgevoerd bij het mounten
return (
<input type="text" ref={inputRef} placeholder="Voer tekst in" />
);
}
export default MyComponent;
Uitleg:
- We maken een ref met
useRef(null). De initiële waarde isnullomdat het input-element nog niet bestaat wanneer de component initieel wordt gerenderd. - We koppelen de ref aan het input-element met de
refprop:ref={inputRef}. React zalinputRef.currentautomatisch instellen op de DOM-node wanneer het input-element wordt gemount. - We gebruiken
useEffectmet een lege dependency array ([]) om ervoor te zorgen dat het effect slechts één keer wordt uitgevoerd nadat de component is gemount. - Binnen het effect controleren we of
inputRef.currentbestaat (om fouten te voorkomen als het element nog niet beschikbaar is) en roepen daninputRef.current.focus()aan om het invoerveld te focussen.
Voorbij DOM-toegang: Muteerbare Waarden Beheren
De ware kracht van useRef ligt in zijn vermogen om muteerbare waarden op te slaan die over renders heen blijven bestaan zonder nieuwe renders te activeren. Dit opent een breed scala aan mogelijkheden voor het optimaliseren van het gedrag van componenten en het beheren van state in functionele componenten.
Voorbeeld: Vorige Prop- of State-waarden Opslaan
Soms moet u toegang krijgen tot de vorige waarde van een prop of state-variabele. useRef biedt een schone manier om dit te doen zonder onnodige re-renders te veroorzaken.
import React, { useRef, useEffect } from 'react';
function MyComponent({ value }) {
const previousValue = useRef(value);
useEffect(() => {
// Update de .current eigenschap van de ref met de huidige waarde
previousValue.current = value;
}, [value]); // Effect wordt uitgevoerd wanneer de 'value' prop verandert
// Nu kunt u de vorige waarde benaderen met previousValue.current
return (
<div>
Huidige waarde: {value}
<br />
Vorige waarde: {previousValue.current}
</div>
);
}
export default MyComponent;
Uitleg:
- We initialiseren de ref
previousValuemet de initiële waarde van devalueprop. - We gebruiken
useEffectom de eigenschappreviousValue.currentbij te werken wanneer devalueprop verandert. - Binnen de component kunnen we nu de vorige waarde van de
valueprop benaderen metpreviousValue.current.
Praktijkvoorbeeld: Wijzigingen in API-reacties Volgen (Internationaal Scenario)
Stel je voor dat je een dashboard bouwt dat wisselkoersen van een API weergeeft. De API kan de koersen in verschillende formaten of met wisselende precisie retourneren, afhankelijk van de gegevensbron (bijv. een API van de Europese Centrale Bank versus een API van een Zuidoost-Aziatische financiële instelling). U kunt useRef gebruiken om de vorige wisselkoers bij te houden en een visuele indicator weer te geven (bijv. een groene pijl omhoog of een rode pijl omlaag) om aan te tonen of de koers is gestegen of gedaald sinds de laatste update. Dit is cruciaal voor internationale gebruikers die op deze koersen vertrouwen voor financiële beslissingen.
Voorbeeld: Tellers of Timers Bijhouden
useRef is perfect voor het beheren van tellers of timers die geen nieuwe renders hoeven te activeren. U kunt het bijvoorbeeld gebruiken om bij te houden hoe vaak op een knop is geklikt of om een eenvoudige timer te implementeren.
import React, { useRef, useState, useEffect } from 'react';
function MyComponent() {
const [count, setCount] = useState(0);
const clickCount = useRef(0); // Initialiseer de ref met 0
const handleClick = () => {
clickCount.current++; // Verhoog de .current eigenschap van de ref
setCount(clickCount.current); // Verhoog de state, wat een re-render veroorzaakt.
};
return (
<div>
<p>Knop geklikt: {count} keer</p>
<button onClick={handleClick}>Klik op mij</button>
</div>
);
}
export default MyComponent;
Uitleg:
- We initialiseren een ref
clickCountmet de waarde 0. - In de
handleClickfunctie verhogen we declickCount.currenteigenschap. Dit activeert geen re-render. - We updaten ook de state 'count', wat een re-render activeert.
Voorbeeld: Een Debounce-functie Implementeren
Debouncing is een techniek die wordt gebruikt om de frequentie waarmee een functie wordt uitgevoerd te beperken. Het wordt vaak gebruikt in zoekinvoervelden om overmatige API-aanroepen te voorkomen terwijl de gebruiker typt. useRef kan worden gebruikt om de timer-ID op te slaan die in de debounce-functie wordt gebruikt.
import React, { useState, useRef, useEffect } from 'react';
function MyComponent() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const timerRef = useRef(null); // Sla de timer-ID op
const handleChange = (event) => {
const newSearchTerm = event.target.value;
setSearchTerm(newSearchTerm);
// Wis de vorige timer als deze bestaat
if (timerRef.current) {
clearTimeout(timerRef.current);
}
// Stel een nieuwe timer in
timerRef.current = setTimeout(() => {
// Simuleer een API-aanroep
fetch(`https://api.example.com/search?q=${newSearchTerm}`)
.then(response => response.json())
.then(data => setResults(data.results));
}, 300); // Debounce voor 300 milliseconden
};
return (
<div>
<input
type="text"
placeholder="Zoeken..."
value={searchTerm}
onChange={handleChange}
/>
<ul>
{results.map(result => (
<li key={result.id}>{result.name}</li>
))}
</ul>
</div>
);
}
export default MyComponent;
Uitleg:
- We gebruiken
useRefom de timer-ID op te slaan intimerRef. - In de
handleChangefunctie wissen we de vorige timer (als die bestaat) metclearTimeout(timerRef.current). - Vervolgens stellen we een nieuwe timer in met
setTimeouten slaan we de timer-ID op intimerRef.current. - De API-aanroep wordt pas gedaan nadat de gebruiker 300 milliseconden is gestopt met typen.
Internationalisatieoverwegingen: Bij het implementeren van debouncing met API-aanroepen die informatie in verschillende talen weergeven, zorg ervoor dat uw API internationalisatie ondersteunt en gegevens retourneert in de voorkeurstaal van de gebruiker. Overweeg het gebruik van de Accept-Language header in uw API-verzoeken.
Voorbeeld: Focus-status Volgen zonder Re-renders
U kunt useRef gebruiken om bij te houden of een element de focus heeft zonder re-renders te veroorzaken. Dit kan handig zijn voor het stijlen van elementen op basis van hun focus-status of voor het implementeren van aangepaste logica voor focusbeheer.
import React, { useRef, useState } from 'react';
function MyComponent() {
const [isFocused, setIsFocused] = useState(false);
const inputRef = useRef(null);
const handleFocus = () => {
setIsFocused(true);
};
const handleBlur = () => {
setIsFocused(false);
};
return (
<div>
<input
type="text"
ref={inputRef}
onFocus={handleFocus}
onBlur={handleBlur}
/>
<p>Input heeft focus: {isFocused ? 'Ja' : 'Nee'}</p>
</div>
);
}
export default MyComponent;
useRef vs. useState: Het Juiste Gereedschap Kiezen
Het is belangrijk om de belangrijkste verschillen tussen useRef en useState te begrijpen om het juiste gereedschap voor de taak te kiezen.
| Kenmerk | useRef | useState |
|---|---|---|
| Activeert Re-render | Nee | Ja |
| Doel | Muteerbare waarden opslaan die geen re-renders hoeven te activeren. Toegang tot DOM-elementen. | State beheren die re-renders moet activeren. |
| Persistentie | Blijft bestaan over re-renders heen. | Blijft bestaan over re-renders heen, maar de waarde wordt bijgewerkt met de setter-functie. |
Best Practices en Veelvoorkomende Valkuilen
- Muteer state niet rechtstreeks: Hoewel
useRefu toestaat waarden rechtstreeks te muteren, vermijd het rechtstreeks muteren van state-variabelen die worden beheerd dooruseState. Gebruik altijd de setter-functie die dooruseStatewordt geleverd om de state bij te werken. - Wees bedacht op bijwerkingen: Wanneer u
useRefgebruikt om waarden te beheren die de UI beïnvloeden, wees dan bedacht op mogelijke bijwerkingen. Zorg ervoor dat uw code zich voorspelbaar gedraagt en geen onverwachte bugs introduceert. - Vertrouw niet op
useRefvoor renderinglogica: Aangezien veranderingen inuseRefgeen re-renders activeren, moet u niet rechtstreeks op de waarden ervan vertrouwen om te bepalen wat er moet worden gerenderd. GebruikuseStatevoor waarden die de renderinglogica moeten aansturen. - Houd rekening met prestatie-implicaties: Hoewel
useRefkan helpen de prestaties te optimaliseren door onnodige re-renders te voorkomen, wees u ervan bewust dat overmatig gebruik van muteerbare waarden uw code moeilijker te doorgronden en te debuggen kan maken.
Geavanceerde Use Cases en Patronen
Waarden Persisteren over Componentinstanties Heen
Hoewel `useRef` waarden persisteert over renders van een *enkele* componentinstantie, hebt u soms een waarde nodig die persisteert over *verschillende* instanties van dezelfde component. Dit vereist een iets andere aanpak, vaak door gebruik te maken van een variabele op moduleniveau in combinatie met `useRef`.
// myComponent.js
let globalCounter = 0; // Variabele op moduleniveau
import React, { useRef, useEffect } from 'react';
function MyComponent() {
const counterRef = useRef(globalCounter); // Initialiseer met de globale waarde
useEffect(() => {
// Update de globale teller wanneer de ref verandert
globalCounter = counterRef.current;
}, [counterRef.current]);
const increment = () => {
counterRef.current++;
// Geen setState nodig, dus geen re-render
};
return (
<div>
<p>Teller: {counterRef.current}</p>
<button onClick={increment}>Verhogen</button>
</div>
);
}
export default MyComponent;
Belangrijke overwegingen: Dit patroon introduceert een globale variabele, dus wees uiterst voorzichtig met mogelijke bijwerkingen en racecondities, vooral in complexe applicaties. Overweeg alternatieve benaderingen zoals het gebruik van een contextprovider als de waarde op een meer gecontroleerde manier tussen meerdere componenten moet worden gedeeld.
Conclusie: De Kracht van useRef Ontketenen
useRef is een veelzijdig hulpmiddel in React dat veel verder gaat dan alleen toegang tot DOM-elementen. Door te begrijpen hoe het muteerbare waarden kan opslaan zonder re-renders te activeren, kunt u uw componenten optimaliseren, de state effectiever beheren en performantere en beter onderhoudbare React-applicaties bouwen. Onthoud dat u het oordeelkundig moet gebruiken en altijd de mogelijke afwegingen tussen prestaties en de duidelijkheid van de code moet overwegen.
Door de patronen in deze gids onder de knie te krijgen, bent u goed uitgerust om het volledige potentieel van useRef in uw React-projecten te benutten, of u nu een eenvoudige webapplicatie of een complex bedrijfssysteem bouwt. Vergeet niet om rekening te houden met internationalisatie en toegankelijkheid wanneer u voor een wereldwijd publiek bouwt!