useImperativeHandle()
Der useImperativeHandle
Hook ist eine spezialisierte Funktion in React, die es ermöglicht, die über ein Ref-Objekt nach außen freigegebene Instanz eines Komponenten anzupassen. Während React generell einen deklarativen Datenfluss bevorzugt, bietet dieser Hook die Möglichkeit, präzise zu kontrollieren, welche Funktionen und Eigenschaften Elternkomponenten durch eine Ref zugänglich gemacht werden. Dies ist besonders nützlich, wenn komplexe Komponenten bestimmte Methoden nach außen exponieren müssen, ohne ihre interne Implementierung vollständig preiszugeben. Der useImperativeHandle
Hook wird typischerweise in Verbindung mit forwardRef
verwendet und ermöglicht eine saubere Kapselung bei gleichzeitiger Bereitstellung einer kontrollierten imperativen API.
Inhaltsverzeichnis
Einführung
Problem verstehen
In React gibt es klassischen Datenfluß. Von oben (Eltern-Komponenten) nach unten (Kind-Komponenten). Das wird in der Regel mit Props umgesetzt. In umgekehrte Richtung (von Kind-Komponente zu Eltern-Komponente) werden normalerweise Callbacks verwendet.
Manchmal benötigt man jedoch eine direkte Möglichkeit als Eltern-Komponente direkt eine Methode in der Kind-Komponente aufzurufen. Genau hier kommt useImperativeHandle
ins Spiel!
Was ist useImperativeHandle
useImperativeHandle
erlaubt es, spezielle Methoden einer Kind-Komponente für die Eltern-Komponente verfügbar zu machen. Damit lässt sich eine Art “Brücke” aufbauen, die diese Verbindung ermöglicht.
Beispiel 1
Am besten lässt sich das anhand einem Beispiel besser verstehen. In diesem Beispiel werden zwei Komponenten definieren.
Kind-Komponente wird ein Eingabe-Feld beinhalten, welches wir über die Eltern-Komponente manipulieren möchten.
Eltern-Komponente wird Buttons (Actions) bereitstellen, mit denen wir etwas mit dem Eingabefeld in der Kind-Komponente tun möchten.
Wir fangen mit der Kind-Komponente an.
import { useRef, useState, useImperativeHandle } from 'react';
function ChildComponent({ props, ref }) {
const [inputValue, setInputValue] = useState('');
const refInputElement = useRef(null);
// Definition von Methoden,
// die von außen aufrufbar sein sollen.
useImperativeHandle(ref, () => {
// Fokus setzen
focusInput: () => {
refInputElement.current.focus();
},
// Wert zurücksetzen
clearInput: () => {
setValue('');
refInputElement.current.focus();
},
// Wert abrufen
getInputValue: () => {
return inputValue;
},
// Spezifischen Wert setzen
setInputValue: (newValue) => {
setInputValue(newValue);
}
});
return (
<div style={{
padding: 20,
boxSizing: 'border-box',
marginBottom: 20,
backgroundColor: '#ffffff'
}}>
<h3>Kind-Komponente (Eingabefeld)</h3>
<input
type="text"
ref={refInputElement}
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Gib etwas ein ..."
style={{
padding: 10,
boxSizing: 'border-box',
fontSize: 14,
border: '2px solid #cccccc',
marginBottom: 10,
widht: '100%'
}}
/>
<div style={{
padding: 10,
boxSizing: 'border-box',
backgroundColor: 'lightblue'
}}>
<span>Aktueller Wert: <strong style={{ color: green }}>{value}</strong></span>
</div>
</div>
);
}
export default ChildComponent;
Nun bauen wir die Eltern-Komponente auf, welche alle Buttons für die Steuerung des Eingabefeldes in der Kind-Komponente beinhaltet.
import { useRef } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const refSpecialInputElement = useRef();
const handleFocusInput = () => {
refSpecialInputElement.current.focusInput();
};
const handleClearInput = () => {
refSpecialInputElement.current.clearInput();
};
const handleGetInputValue = () => {
const currentValue = refSpecialInputElement.current.getInputValue();
console.log(`Aktueller Wert: ${currentValue}`);
};
const handleSetInputValue = () => {
refSpecialInputElement.current.setInputValue('Das ist ein Test-Wert');
};
return (
<div
className="app-wrapper"
style={{
padding: 20,
border: '2px solid #aaaaaa',
borderRadius: 8,
boxSizing: 'border-box',
backgroundColor: '#eeeeee'
}}
>
<h2>Eltern-Komponente (Steuerung)</h2>
<ChildComponent ref={refSpecialInputElement} />
<div
className="controls"
style={{
display: 'grid',
gridTemplateColumns: '1fr 1fr',
gridGap: 20
}}
>
<button onClick={handleFocusInput}>
Fokus setzen
</button>
<button onClick={handleClearInput}>
Leeren
</button>
<button onClick={handleGetInputValue}>
Wert abrufen (Konsole)
</button>
<button onClick={handleSetInputValue}>
Wert setzen
</button>
</div>
</div>
);
}
export default ParentComponent;
Als Ergebnis haben wir eine Applikation, in welcher wir aus der Eltern-Komponente Funktionen in der Kind-Komponente aufrufen können.