Einführung
React Referenzen (Refs) ermöglichen den direkten Zugriff auf DOM-Elemente oder Komponenteninstanzen, um beispielsweise Fokussteuerung, Animationen oder Integration mit Drittanbieter-Bibliotheken zu realisieren. Portale erweitern dieses Konzept, indem sie es erlauben, React-Komponenten außerhalb der regulären DOM-Hierarchie zu rendern. Dies ist besonders nützlich für modale Fenster, Tooltips oder Overlays, die unabhängig vom normalen Komponentenbaum dargestellt werden sollen. Zusammen bilden Refs und Portale grundlegende Werkzeuge, um erweiterte Interaktionen und komplexe UI-Strukturen in React-Anwendungen umzusetzen.
Inhaltsverzeichnis
Problem
Verwendung von Formularen ohne spezifische Unterstützung seitens React Hooks kann etwas umständlich sein. Man steht immer vor der Aufgabe an die Werte aus den Formularen heran zu kommen.
Damit wir besser verstehen was gemeint ist und ein Beispiel vor Augen haben, definieren wir folgendes Component.
import { useState } from 'react';
const FormWithoutRef = () => {
const [fieldUsername, setFieldUsername] = useState('');
const handleUpdateUsername = (event) => {
setFieldUsername(event.target.value);
};
const handleSubmitForm = (event) => {
event.preventDefault();
// Hier z.B. Daten an den Server senden
};
return (
<form onSubmit={handleSubmitForm}>
<label htmlFor="fieldUsername">Benutzername</label>
<input
type="text"
id="fieldUsername"
name="fieldUsername"
onChange={handleUpdateUsername}
/>
<button>Submit</button>
</form>
);
};
export default FormWithoutRef;
Technisch funktioniert dieses Beispiel, ist aber einiges an Code. In diesem Beispiel benötigen wir die Zustandsverwaltung hauptsächlich für das Auslesen des Benutzernamens, um es an den Server zu senden.
Obwohl fieldUsername
eigentlich von der Funktion handleSubmitForm()
benötigt wird, führt React den gesamten Code des Components aus, wenn ein change
-Event durch die Eingabe im Input-Feld ausgelöst wird. Also, bei jeder Tasteneingabe.
An dieser Stelle könnte man all diese Ausführungen durch React und u.U. auch etwas an Performance einsparen, indem man auf Vanilla JavaScript umsteigt und die Felder in etwa wie folgt ausliest.
const inputUsername = document.getElementById("fieldUsername");
const usernameValue = inputUsername.value;
Das Problem an dieser Herangehensweise ist, dass hier kein React verwendet wird. Und wenn man mit React eine Anwendung aufbaut, sollte man unbedingt innerhalb von React bleiben.
Versuche, JavaScript am React vorbei oder nicht nach React-Art einzusetzen, könnten im fehlerhaften und unerwarteten Verhalten enden. Vor allem, wenn es um die UI-Aktualisierung geht. Macht man hier etwas nicht nach React-Art, kann es ebenfalls Probleme geben.
Lösung - useRef()
Um uns dennoch auf native DOM-Elemente zugreifen zu lassen, stellt uns React den Kontext “Refs” (References oder Referenzen) bereit. Referenzen (Ref) ist eine Möglichkeit, Referenzen auf Werte zu speichern, beispielsweise auf DOM-Elemente, aus einem Component heraus.
Um eine Referenz zu erzeugen, gibt es useRef()
Hook. Damit kann man eine Referenz erstellen.
Irgendwo im Code können wir also Folgendes tun.
import { useRef } from 'react';
const MyComponent = () => {
const refFieldUsername = useRef(null);
};
export default MyComponent;
Damit haben wir eine Referenz erzeugt, welche leer (null) ist. Wir können nun in unserem JSX-Template diese Referenz an ein DOM-Element binden und dadurch den Zugriff auf dieses Element über diese Referenz (Brücke) zu erhalten.
Nun stellen wir unser Beispiel auf die Verwendung von useRef()
um.
import { useState } from 'react';
const FormWithRef = () => {
const refFieldUsername = useRef(null);
const handleSubmitForm = (event) => {
event.preventDefault();
console.log(refFieldUsername.current.value);
};
return (
<form onSubmit={handleSubmitForm}>
<label htmlFor="fieldUsername">Benutzername</label>
<input
type="text"
id="fieldUsername"
name="fieldUsername"
ref={refFieldUsername}
/>
<button>Submit</button>
</form>
);
};
export default FormWithRef;
Wichtiger Hinweis
Um das Element aus dem Referenz-Objekt (Rückgabewert der useRef()
Funktion) anzusprechen, müssen wir über die current
Eigenschaft gehen. Anders formuliert: In current
befindet sich die Referenz auf das Objekt.
Als Ergebnis haben wir das identische Formular und beim Klick auf den Submit-Button oder durch das Auslösen des submit
-Events erhalten wir den Wert des referenzierten Eingabefeldes in Konsole ausgegeben.
In diesem Beispiel erhält die useRef()
Funktion null
als initialen Startwert übergeben, da es technisch noch keinem DOM-Element zugewiesen wurde, wenn die Component-Funktion (FormWithRef
) zum ersten Mal ausgeführt wird. Eine Referenzierung erfolgt erst nach dem initialen Render-Vorgang.
Nach der ersten Ausführung wird der Wert von useRef()
das referenzierte DOM-Element sein.
Um den Wert nach der initialen Ausführung erneut zu prüfen, simulieren wir es mithilfe von useState()
und einem völlig sinnlosen Wert. Wie wir wissen, wird die Component-Funktion beim Aufruf der State-Update-Funktion erneut ausgeführt.
Wir aktualisieren unser Beispiel-Code wie folgt und schauen was wir in der Konsole nach dem Klick auf den Button “Update value” erhalten.
import { useRef, useState } from 'react';
const FormWithRef = () => {
const [sampleValue, setSampleValue] = useState(0);
const refFieldUsername = useRef(null);
console.log('Direct after assignment', refFieldUsername);
const handleUpdateSampleValue = () => {
setSampleValue(current => 1);
};
const handleSubmitForm = (event) => {
event.preventDefault();
console.log(refFieldUsername.current.value);
};
return (
<form onSubmit={handleSubmitForm}>
<label htmlFor="fieldUsername">Benutzername</label>
<input
type="text"
name="fieldUsername"
id="fieldUsername"
ref={refFieldUsername}
/>
<button>Submit</button>
<button onClick={handleUpdateSampleValue}>Update value</button>
</form>
);
};
export default FormWithRef;