Hooks API Referenz
Hooks sind ein neues Feature in React 16.8. Damit lassen sich State und andere React Features nutzen, ohne dass eine Klasse geschrieben werden muss.
Diese Seite beschreibt die APIs für die bereits in React implementierten Hooks.
Wenn Hooks neu für dich sind, schau dir zuerst den Überblick an. Nützliche Informationen findest du außerdem in den häufig gestellten Fragen.
Grundlegende Hooks
useState
const [state, setState] = useState(initialState);
Gibt einen zustandsbezogenen (engl. stateful) Wert zurück und eine Funktion, um diesen zu aktualisieren.
Während des initialen Renderns ist der zurückgegebene State (state
) derselbe Wert, der als erstes Argument (initialState
) übergeben wird.
Die Funktion setState
wird verwendet, um den State zu aktualisieren. Sie akzeptiert einen neuen Wert für den State und veranlasst ein erneutes Rendern der Komponente.
setState(newState);
Bei nachfolgenden Re-Renderings ist der erste Wert, der von useState
zurückgegeben wird, immer der letzte State nach der Anwendung von Updates.
Hinweis
React garantiert, dass die Identität der
setState
-Funktion stabil ist und sie sich auch bei erneutem Rendern nicht ändert. Deshalb kann die Funktion problemlos aus der Liste der Abhängigkeiten desuseEffect
oderuseCallback
ausgelassen werden.
Aktualisieren mithilfe einer Funktion
Wenn der neue State mit Hilfe des vorherigen States ermittelt werden soll, kannst du eine Funktion an setState
übergeben. Diese Funktion nimmt den vorherigen Wert entgegen und gibt den aktualisierten Wert zurück. Das folgende Beispiel einer Counter-Komponente nutzt beide Formen von setState
:
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Aktueller Wert: {count}
<button onClick={() => setCount(initialCount)}>Zurücksetzen</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
</>
);
}
Die Buttons ”+” und ”-” nutzen eine Funktion, weil der aktualisierte Wert auf dem vorherigen beruht. Der “Zurücksetzen”-Button dagegen benutzt die normale Form, weil er den Zähler immer auf den initialen Wert zurücksetzt.
Wenn die Aktualisierungsfunktion exakt denselben Wert wie der aktuelle State zurückgibt, wird das darauf folgende erneute Rendern vollständig übersprungen.
Hinweis
Anders als die
setState
-Methode in Klassenkomponenten führtuseState
aktualisierte Objekte nicht automatisch zusammen. Du kannst dieses Verhalten nachahmen, indem du die spread-Syntax für Objekte mit einer Aktualisierungsfunktion verbindest:const [state, setState] = useState({}); setState(prevState => { // Object.assign würde auch funktionieren return {...prevState, ...updatedValues}; });
Eine andere Option ist
useReducer
, was sich aber eher eignet, wenn man State-Objekte verwaltet, die mehrere Teilwerte enthalten.
Lazy initialer State
Das initialState
-Argument ist der State, der während des initialen Renderns benutzt wird. Bei nachfolgendem Rendern wird er nicht beachtet. Wenn der initiale State das Ergebnis einer aufwendigen Berechnung ist, kannst Du stattdessen auch eine Funktion angeben, die nur beim ersten Rendern ausgeführt wird:
const [state, setState] = useState(() => {
const initialState = someExpensiveComputation(props);
return initialState;
});
Abbruch der State-Aktualisierung
Wenn du eine State-Hook auf den gleichen Wert wie den aktuellen aktualisierst, wird React den Vorgang abbrechen, ohne die Kindelemente zu rendern oder Effekte auszulösen. (React benutzt den Object.is
-Vergleichsalgorithmus.)
Beachte, dass React diese spezielle Komponente möglicherweise noch einmal rendern muss, bevor es den Vorgang abbricht. Das sollte kein Problem sein, da React nicht unnötig “tiefer” in den Baum eindringt. Wenn du während des Renderns umfangreiche Berechnungen durchführst, kannst du diese mit useMemo
optimieren.
Bündeln von State-Aktualisierungen
React kann mehrere State-Aktualisierungen in einem einzigen erneuten Rendern zusammenfassen, um die Performance zu verbessern. Normalerweise verbessert dies die Performance und sollte keine Auswirkungen auf das Verhalten der Anwendung haben.
Vor React 18 wurden nur Aktualisierungen innerhalb von React-Event-Handlern gebündelt. Seit React 18 ist die gebündelte Verarbeitung für alle Aktualisierungen standardmäßig aktiviert. Beachte, dass React sicherstellt, dass Aktualisierungen von mehreren verschiedenen benutzerinitiierten Ereignissen - z.B. zweimaliges Klicken auf eine Schaltfläche - immer separat verarbeitet und nicht zusammengeführt werden. Dies verhindert logische Fehler.
In dem seltenen Fall, dass du die synchrone Anwendung der DOM-Aktualisierung erzwingen musst, kannst du sie in flushSync
verpacken. Dies kann jedoch die Performance beeinträchtigen, weshalb du dies nur bei Bedarf tun solltest.
useEffect
useEffect(didUpdate);
Akzeptiert eine Funktion, die imperativen Code enthält, der möglicherweise auch einen Effekt hat.
Innerhalb des Hauptteils von funktionalen Komponenten (in React als render phase bezeichnet) sind Mutationen, Subscriptions, Timer, das Loggen und andere Nebeneffekte (engl. side effects) nicht erlaubt. Dies hätte nämlich verwirrende Fehler und Ungereimtheiten in der UI zur Folge.
Benutze stattdessen useEffect
. Die Funktion, die an useEffect
übergeben wird, wird ausgeführt, nachdem das Rendern an den Bildschirm übertragen worden ist. Effekte sind also die Möglichkeit, aus der rein funktionalen Welt von React in die imperative Welt zu entfliehen.
Standardmäßig werden die Effekte nach jedem abgeschlossenen Rendern ausgeführt, aber du kannst festlegen, dass sie nur ausgelöst werden, wenn sich bestimmte Werte geändert haben.
Bereinigung eines Effekts
Effekte erzeugen häufig Ressourcen, die bereinigt werden müssen, bevor die Komponente den Bildschirm verlässt, wie etwa ein Abonnement oder eine Timer-ID. Zu diesem Zweck kann die an useEffect
übergebene Funktion eine Aufräumfunktion zurückgeben. Zum Beispiel, um eine Subscription zu erstellen:
useEffect(() => {
const subscription = props.source.subscribe();
return () => {
// Bereinigen des Abonnements
subscription.unsubscribe();
};
});
Die Aufräumfunktion wird ausgeführt, bevor die Komponente aus der Benutzeroberfläche entfernt wird, um Speicherprobleme zu vermeiden. Wenn eine Komponente mehrfach gerendert wird (was in der Regel der Fall ist), wird außerdem der vorherige Effekt bereinigt, bevor der nächste Effekt ausgeführt wird. In unserem Beispiel bedeutet dies, dass bei jeder Aktualisierung eine neue Subscription erstellt wird. Um zu vermeiden, dass bei jeder Aktualisierung ein Effekt ausgelöst wird, schau Dir den nächsten Abschnitt an.
Zeitlicher Ablauf der Effekte
Im Gegensatz zu componentDidMount
und componentDidUpdate
wird die Funktion, die an useEffect
übergeben wird, nach dem Layouten und Malen (engl. paint), während eines verzögerten Ereignisses, ausgelöst. Deshalb ist useEffect
geeignet für die vielen häufigen Nebeneffekte, wie die Einrichtung von Subscriptions und Event Handlern, weil die meisten dieser Arbeiten den Browser nicht dabei blockieren sollten, den Bildschirm zu aktualisieren.
Allerdings können nicht alle Auswirkungen aufgeschoben (engl. deferred) werden. So muss beispielsweise eine DOM-Mutation, die für den Benutzer sichtbar ist, synchron vor dem nächsten Malvorgang erfolgen, damit der Benutzer keine visuelle Inkonsistenz wahrnimmt. (Die Unterscheidung ist konzeptionell ähnlich wie die zwischen passiven und aktiven Event Listenern). Für diese Arten von Effekten bietet React einen zusätzlichen Hook namens useLayoutEffect
. Dieser hat die gleiche Signatur wie useEffect
und unterscheidet sich nur darin, wann er ausgelöst wird.
Zusätzlich wird ab React 18 die Funktion, die an useEffect
übergeben wird, synchron vor dem Layouten und dem Malen ausgelöst, wenn sie das Ergebnis einer diskreten Benutzereingabe wie einem Klick ist, oder wenn sie das Ergebnis einer Aktualisierung ist, die in flushSync
verpackt ist. Dieses Verhalten ermöglicht es, dass das Ergebnis des Effekts vom Ereignissystem oder vom Aufrufer von flushSync
beobachtet werden kann.
Hinweis
Dies wirkt sich nur auf den Zeitpunkt aus, zu dem die an
useEffect
übergebene Funktion aufgerufen wird - Aktualisierungen, die innerhalb dieser Effekte geplant sind, werden weiterhin aufgeschoben. Darin liegt der Unterschied zuuseLayoutEffect
, wo die Funktion ausgelöst und die Aktualisierungen innerhalb der Funktion sofort verarbeitet werden.
Sogar in Fällen, in denen useEffect
aufgeschoben wird, bis der Browser gezeichnet hat, ist garantiert, dass es vor jedem neuen Rendering ausgelöst wird. React wird immer die Effekte eines vorherigen Renderings löschen, bevor eine neue Aktualisierung gestartet wird.
Bedingte Auslösung eines Effekts
Standardmäßig wird der Effekt nach jedem abgeschlossenen Rendering ausgelöst. Auf diese Weise wird ein Effekt immer neu erstellt, wenn sich eine seiner Abhängigkeiten ändert.
In manchen Fällen kann dies jedoch zu viel sein, wie im Beispiel der Subscription aus dem vorherigen Abschnitt. Wir müssen nicht bei jeder Aktualisierung eine neue Subscription erstellen, sondern nur dann, wenn sich die source
Prop geändert hat.
Um dies zu implementieren, kannst du ein zweites Argument an useEffect
übergeben, welches das Array derjenigen Werte ist, von denen der Effekt abhängt. Unser aktualisiertes Beispiel sieht nun wie folgt aus:
useEffect(
() => {
const subscription = props.source.subscribe();
return () => {
subscription.unsubscribe();
};
},
[props.source],
);
Jetzt wird die Subscription nur neu erstellt, wenn sich props.source
ändert.
Hinweis
Wenn du diese Optimierung verwendest, musst du sicherstellen, dass das Array alle Werte aus dem Geltungsbereich der Komponente (z. B. Props und State) enthält, die sich im Laufe der Zeit ändern und die vom Effekt verwendet werden. Andernfalls verweist der Code auf veraltete Werte aus früheren Renderings. Lerne mehr darüber, wie man mit Funktionen umgeht und was zu tun ist, wenn sich die Werte des Arrays zu oft ändern.
Wenn du einen Effekt nur einmal ausführen und aufräumen willst (beim Erstellen und Löschen), kannst du ein leeres Array (
[]
) als zweites Argument übergeben. Dies teilt React mit, dass der Effekt nicht von irgendwelchen Werten von Props oder State abhängt, so dass er nie wieder ausgeführt werden muss. Dies wird nicht als Sonderfall behandelt - es ergibt sich direkt daraus, wie das Abhängigkeits-Array immer funktioniert.Wenn man ein leeres Array (
[]
) übergibt, haben die Props und der State innerhalb des Effekts immer ihre initialen Werte. Während die Übergabe von[]
als zweites Argument dem bekannten mentalen Modell voncomponentDidMount
undcomponentWillUnmount
näher kommt, gibt es normalerweise bessere Lösungen, um eine zu häufige Wiederholung der Effekte zu vermeiden. Man sollte auch nicht vergessen, dass React die Ausführung vonuseEffect
aufschiebt, bis der Browser gezeichnet hat, so dass zusätzlicher Aufwand weniger ein Problem darstellt.Wir empfehlen, die
exhaustive-deps
-Regel als Teil unsereseslint-plugin-react-hooks
-Packages zu benutzen. Es warnt, wenn Abhängigkeiten falsch angegeben sind, und schlägt eine Korrektur vor.
Das Array der Abhängigkeiten wird nicht als Argument an die Effektfunktion übergeben. Konzeptionell ist es jedoch genau das: Jeder Wert, auf den innerhalb der Effektfunktion verwiesen wird, sollte auch im Array der Abhängigkeiten erscheinen. In Zukunft könnte ein ausreichend fortgeschrittener Compiler dieses Array automatisch erstellen.
useContext
const value = useContext(MyContext);
Akzeptiert ein Kontextobjekt (den von React.createContext
zurückgegebenen Wert) und gibt den aktuellen Kontextwert für diesen Kontext zurück. Der aktuelle Kontextwert wird durch die value
-Prop des nächstgelegenen <MyContext.Provider>
oberhalb der aufrufenden Komponente im Baum bestimmt.
Sobald sich der nächstgelegene <MyContext.Provider>
oberhalb der Komponente aktualisiert, löst dieser Hook ein erneutes Rendering mit dem neuesten Kontext-value
aus, der an den MyContext
-Provider übergeben worden ist. Auch, wenn ein Vorfahre React.memo
benutzt oder shouldComponentUpdate
, wird ein erneutes Rendering immer noch von der Komponente selbst ausgehend unter Verwendung von useContext
erfolgen.
Das Argument für useContext
muss dabei das Kontextobjekt selbst sein:
- Korrekt:
useContext(MyContext)
- Inkorrekt:
useContext(MyContext.Consumer)
- Inkorrekt:
useContext(MyContext.Provider)
Eine Komponente, die useContext
aufruft, wird immer neu gerendert, wenn sich der Kontextwert ändert. Wenn ein erneutes Rendering aufwendig ist, kann man es mit Hilfe von Memoisierung optimieren.
Tipp
Wenn du mit der Kontext-API vor Hooks vertraut bist, ist
useContext(MyContext)
gleichbedeutend mitstatic contextType = MyContext
in einer Klasse, oder mit<MyContext.Consumer>
.Mit
useContext(MyContext)
kann man den Kontext nur lesen und auf dessen Änderungen hören. Man benötigt immer noch einen<MyContext.Provider>
weiter oben im Baum, um den Wert für diesen Kontext bereitzustellen.
Zusammenstellung mit Context.Provider
const themes = {
light: {
foreground: "#000000",
background: "#eeeeee"
},
dark: {
foreground: "#ffffff",
background: "#222222"
}
};
const ThemeContext = React.createContext(themes.light);
function App() {
return (
<ThemeContext.Provider value={themes.dark}>
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar(props) {
return (
<div>
<ThemedButton />
</div>
);
}
function ThemedButton() {
const theme = useContext(ThemeContext); return ( <button style={{ background: theme.background, color: theme.foreground }}> Ich bin gestylt mit Hilfe des theme-Kontextes! </button> );
}
Dieses Beispiel wurde für Hooks von einem früheren Beispiel im fortgeschrittenen Guide zum Kontext abgeändert, wo sich weitere Informationen darüber finden, wann und wie man Context verwenden kann.
Zusätzliche Hooks
Die folgenden Hooks sind entweder Varianten der grundlegenden Hooks aus dem vorigen Abschnitt oder werden nur für bestimmte Sonderfälle benötigt. Es besteht also kein Grund, sie im Voraus zu lernen.
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
Eine Alternative zu useState
. Akzeptiert einen Reducer vom Typ (state, action) => newState
, und gibt den aktuellen State zusammen mit einer dispatch
-Methode zurück. (Wenn du mit Redux vertraut bist, weißt du bereits, wie das funktioniert.)
useReducer
ist in der Regel besser als useState
, wenn man eine komplexe Statelogik hat, die mehrere Teilwerte umfasst, oder wenn der nächste State vom vorherigen abhängt. Mit useReducer
lässt sich auch die Leistung für Komponenten optimieren, die tiefe Aktualisierungen auslösen, weil man dispatch
anstelle von Callbacks weitergeben kann.
Hier ist das Beispiel eines Counters aus dem Abschnitt useState
, umgeschrieben mithilfe eines Reducers:
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Aktueller Wert: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Hinweis
React garantiert, dass die Identität der Funktion
dispatch
stabil ist und sich bei erneuten Renderings nicht ändert. Deshalb kann die Funktion problemlos aus der Liste der Abhängigkeiten vonuseEffect
oderuseCallback
ausgelassen werden.
Festlegen des initialen States
Es gibt zwei verschiedene Möglichkeiten, den State von useReducer
zu initialisieren. Je nach Anwendungsfall kann man eine der beiden Möglichkeiten wählen. Der einfachste Weg ist die Übergabe des Ausgangszustands als zweites Argument:
const [state, dispatch] = useReducer(
reducer,
{count: initialCount} );
Hinweis
React verwendet nicht die Konvention
state = initialState
, die durch Redux populär wurde. Der Anfangswert muss manchmal von den Props abhängen und wird daher stattdessen beim Hook-Aufruf angegeben. Wenn dir das wichtig ist, kannst duuseReducer(reducer, undefined, reducer)
aufrufen, um das Redux-Verhalten nachzuahmen, aber das ist nicht empfehlenswert.
Verzögerte Initialisierung
Man kann den initialen Wert auch verzögert erstellen. Dafür muss man eine init
-Funktion als drittes Argument übergeben. Der initiale State wird dann auf init(initialArg)
gesetzt.
Hierdurch wird die Logik, um den initialen State zu kalkulieren, aus dem Reducer ausgelagert. Das ist auch dann nützlich, wenn der State später in Reaktion auf eine Handlung zurückgesetzt werden soll:
function init(initialCount) { return {count: initialCount};}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
case 'reset': return init(action.payload); default:
throw new Error();
}
}
function Counter({initialCount}) {
const [state, dispatch] = useReducer(reducer, initialCount, init); return (
<>
Aktueller Wert: {state.count}
<button
onClick={() => dispatch({type: 'reset', payload: initialCount})}> Zurücksetzen
</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
Abbruch des Dispatch
Wenn du vom Reducer-Hook denselben Wert zurückgibst wie der aktuelle State, wird React den Vorgang abbrechen, ohne die Kind-Elemente zu rendern oder Effekte auszulösen. (React benutzt den Object.is
Vergleichsalgorithmus.)
Beachte, dass React diese spezielle Komponente möglicherweise noch einmal rendern muss, bevor es den Vorgang abbricht. Das sollte kein Problem sein, da React nicht unnötig “tiefer” in den Baum eindringt. Wenn du während des Renderns umfangreiche Berechnungen durchführst, kannst du diese mit useMemo
optimieren.
useCallback
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Gibt einen memoisierten Callback zurück.
Übergib ein Inline-Callback und ein Array von Abhängigkeiten. useCallback
wird eine memoisierte Version des Callbacks zurückgeben, die sich nur dann ändert, wenn sich eine der Abhängigkeiten geändert hat. Das ist nützlich, um Callbacks an optimierte Kindkomponenten zu übergeben, die sich auf gleichbleibende Referenzen verlassen, um unnötigem Rendern vorzubeugen (e.g. shouldComponentUpdate
).
useCallback(fn, deps)
ist gleichbedeutend mit useMemo(() => fn, deps)
.
Hinweis
Das Array der Abhängigkeiten wird nicht als Argument an den Callback übergeben. Konzeptionell ist es jedoch genau das: Jeder Wert, auf den innerhalb des Callbacks verwiesen wird, sollte auch im Array der Abhängigkeiten erscheinen. In Zukunft könnte ein ausreichend fortgeschrittener Compiler dieses Array automatisch erstellen.
Wir empfehlen, die
exhaustive-deps
-Regel als Teil unsereseslint-plugin-react-hooks
-Packages zu benutzen. Es warnt, wenn Abhängigkeiten falsch angegeben sind, und schlägt eine Korrektur vor.
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
Gibt einen memoisierten Wert zurück.
Übergib eine “create”-Funktion und ein Array von Abhängigkeiten. useMemo
wird den memoisierten Wert nur dann neu berechnen, wenn sich eine der Abhängigkeiten geändert hat. Diese Optimierung hilft dabei, aufwendige Berechnungen bei jedem Rendern zu vermeiden.
Beachte, dass die Funktion, die an useMemo
übergeben wird, während des Renderns abläuft. Vermeide es, dort irgendetwas zu tun, was du normalerweise während des Renderns tun würdest. Seiteneffekte zum Beispiel gehören in useEffect
, nicht in useMemo
.
Wenn kein Array angegeben wird, wird der Wert bei jedem Rendern berechnet.
Du könntest dich auf useMemo
als Leistungsoptimierung verlassen, anstatt es als semantische Garantie anzusehen. In der Zukunft könnte React sich dafür entscheiden, einige zuvor memoisierte Werte zu “vergessen” und sie beim nächsten Rendern neu zu berechnen, z.B. um Speicher für Offscreen-Komponenten freizugeben. Schreibe deinen Code deshalb so, dass er auch ohne useMemo
funktioniert - und dann füge ihn hinzu, um die Leistung zu optimieren.
Hinweis
Das Array der Abhängigkeiten wird nicht als Argument an die Funktion übergeben. Konzeptionell ist es jedoch genau das: Jeder Wert, auf den innerhalb der Funktion verwiesen wird, sollte auch im Array der Abhängigkeiten erscheinen. In Zukunft könnte ein ausreichend fortgeschrittener Compiler dieses Array automatisch erstellen.
Wir empfehlen, die
exhaustive-deps
-Regel als Teil unsereseslint-plugin-react-hooks
-Packages zu benutzen. Es warnt, wenn Abhängigkeiten falsch angegeben sind, und schlägt eine Korrektur vor.
useRef
const refContainer = useRef(initialValue);
useRef
gibt ein veränderbares ref-Objekt zurück, dessen Eigenschaft .current
mit dem übergebenen Argument (initialValue
) initialisiert wird. Das zurückgegebene Objekt bleibt während der gesamten Lebensdauer der Komponente bestehen.
Ein häufiger Anwendungsfall ist der imperative Zugriff auf ein Kind:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` zeigt auf das gemountete Texteingabeelement
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Fokussiere das Inputfeld</button>
</>
);
}
Im Wesentlichen ist useRef
wie eine “Box”, die einen veränderbaren Wert in ihrer Eigenschaft .current
enthalten kann.
Du kennst Refs vielleicht in erster Linie als eine Möglichkeit auf das DOM zuzugreifen. Wenn du ein Ref-Objekt an React mit <div ref={myRef} />
übergibst, wird React dessen Eigenschaft .current
auf den entsprechenden DOM-Knoten setzen, sobald sich dieser ändert.
useRef()
ist jedoch nicht nur für das ref
-Attribut nützlich. Es ist praktisch, um einen veränderlichen Wert zu behalten, ähnlich wie man Instanzfelder in Klassen verwenden würde.
Das funktioniert, weil useRef()
ein einfaches JavaScript-Objekt erzeugt. Der einzige Unterschied zwischen useRef()
und der Erstellung eines {current: ...}
-Objekts ist, dass useRef
bei jedem Rendering das gleiche ref-Objekt erzeugt.
Beachte, dass useRef
dich nicht benachrichtigt, wenn sich sein Inhalt ändert. Die Änderung der .current
-Eigenschaft führt nicht zu einem erneuten Rendern. Wenn du einen Code ausführen möchtest, sobald React eine Ref an einen DOM-Knoten anhängt oder abnimmt, solltest du stattdessen einen callback ref verwenden.
useImperativeHandle
useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle
passt den Instanzwert an, der bei der Verwendung von ref
für übergeordnete Komponenten sichtbar ist. Wie immer sollte imperativer Code mit Refs in den meisten Fällen vermieden werden. useImperativeHandle
sollte mit forwardRef
verwendet werden:
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
In diesem Beispiel wäre eine übergeordnete Komponente, die <FancyInput ref={inputRef} />
rendert, in der Lage inputRef.current.focus()
aufzurufen.
useLayoutEffect
Die Signatur dieser Hook ist identisch mit useEffect
, aber er wird synchron nach allen DOM-Mutationen ausgelöst. Verwende ihn, um das Layout aus dem DOM zu lesen und synchron neu zu rendern. Aktualisierungen, die innerhalb von useLayoutEffect
geplant sind, werden synchron vorgenommen, bevor der Browser die Chance hat zu malen.
Bevorzuge, wenn möglich, den Standard useEffect
, um zu vermeiden, dass visuelle Aktualisierungen blockiert werden.
Tipp
Wenn du Code von einer Klassenkomponente migrierst, beachte, dass
useLayoutEffect
in der gleichen Phase ausgelöst wird wiecomponentDidMount
undcomponentDidUpdate
. Wir empfehlen aber, zuerst mituseEffect
zu beginnen unduseLayoutEffect
nur dann auszuprobieren, wenn dies ein Problem verursacht.Wenn du Server-Rendering verwendest, beachte, dass weder
useLayoutEffect
nochuseEffect
ausgeführt werden können, bis das JavaScript heruntergeladen ist. Aus diesem Grund warnt React, wenn eine vom Server gerenderte KomponenteuseLayoutEffect
enthält. Um dies zu beheben, verschiebe entweder diese Logik zuuseEffect
(wenn sie für das erste Rendern nicht notwendig ist), oder verzögere die Anzeige dieser Komponente bis nach dem Rendern des Clients (wenn das HTML kaputt aussieht, bisuseLayoutEffect
läuft).Um eine Komponente, die Layout-Effekte benötigt, von dem vom Server gerenderten HTML auszuschließen, rendere sie bedingt mit
showChild && <Child />
und verzögere ihre Anzeige mituseEffect(() => { setShowChild(true); }, [])
. Auf diese Weise erscheint die Benutzeroberfläche vor der Hydration nicht beschädigt.
useDebugValue
useDebugValue(value)
useDebugValue
kann verwendet werden, um ein Label für eigene Hooks in den React DevTools anzuzeigen.
Betrachten wir zum Beispiel den benutzerdefinierten Hook useFriendStatus
, der in “Eigene Hooks bauen” beschrieben wird:
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
// ...
// Zeige ein Label in den DevTools neben diesem Hook an // z.B. "FriendStatus: Online" useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}
Tipp
Wir empfehlen nicht, Debug-Werte zu jedem eigenen Hook hinzuzufügen. Dies ist am nützlichsten für eigene Hooks, die Teil von gemeinsam genutzten Libraries sind.
Aufschieben der Formatierung von Debug-Werten
In einigen Fällen kann die Formatierung eines Wertes für die Anzeige ein aufwendiger Vorgang sein. Sie ist auch unnötig, es sei denn, ein Hook wird tatsächlich inspiziert.
Aus diesem Grund akzeptiert useDebugValue
eine Formatierungsfunktion als optionalen zweiten Parameter. Diese Funktion wird nur aufgerufen, wenn die Hooks inspiziert werden. Sie erhält den Debug-Wert als Parameter und sollte einen formatierten Anzeigewert zurückgeben.
Ein eigener Hook, der einen Date
-Wert zurückgegeben hat, könnte beispielsweise den unnötigen Aufruf der toDateString
-Funktion vermeiden, indem er den folgenden Formatierer übergibt:
useDebugValue(date, date => date.toDateString());
useDeferredValue
const deferredValue = useDeferredValue(value);
useDeferredValue
akzeptiert einen Wert und gibt eine neue Kopie des Wertes zurück, die auf dringendere Aktualisierungen warten wird. Wenn das aktuelle Rendering das Ergebnis einer dringenden Aktualisierung ist, wie z.B. einer Benutzereingabe, gibt React den vorherigen Wert zurück und rendert dann den neuen Wert, nachdem das dringende Rendering abgeschlossen ist.
Dieser Hook ähnelt den User-Space-Hooks, die durch Entprellung (engl. debouncing) oder Drosselung Aktualisierungen aufschieben. Der Vorteil der Verwendung von useDeferredValue
ist, dass React an der Aktualisierung arbeitet, sobald andere Arbeiten beendet sind (anstatt auf eine beliebige Zeitspanne zu warten), und wie startTransition
können aufgeschobene Werte ausgesetzt werden, ohne einen unerwarteten Fallback für bestehende Inhalte auszulösen.
Memoisierte aufgeschobene Kinder
useDeferredValue
verschiebt nur den Wert, den man übergibt. Wenn du verhindern willst, dass eine untergeordnete Komponente während einer dringenden Aktualisierung neu gerendert wird, musst du diese Komponente auch mit React.memo
oder React.useMemo
memoisieren:
function Typeahead() {
const query = useSearchQuery('');
const deferredQuery = useDeferredValue(query);
// Memoisierung weist React an, nur neu zu rendern, wenn sich deferredQuery ändert,
// und nicht, wenn sich die Abfrage ändert.
const suggestions = useMemo(() =>
<SearchSuggestions query={deferredQuery} />,
[deferredQuery]
);
return (
<>
<SearchInput query={query} />
<Suspense fallback="Loading results...">
{suggestions}
</Suspense>
</>
);
}
Die Kinder zu memoisieren sagt React, dass sie nur neu gerendert werden müssen, wenn sich deferredQuery
ändert, und nicht, wenn sich query
ändert. Dieser Vorbehalt gilt nicht nur für useDeferredValue
, sondern auch für ähnliche Hooks, die Entprellung (engl. debouncing) oder Drosselung verwenden.
useTransition
const [isPending, startTransition] = useTransition();
Gibt einen zustandsbezogenen Wert für den anstehenden State der Transition und eine Funktion zum Starten dieser zurück.
Mit startTransition
können Aktualisierungen in dem angegebenen Callback als Übergänge markiert werden:
startTransition(() => {
setCount(count + 1);
});
isPending
markiert, wenn eine Transition aktiv ist, um einen ausstehenden State anzuzeigen:
function App() {
const [isPending, startTransition] = useTransition();
const [count, setCount] = useState(0);
function handleClick() {
startTransition(() => {
setCount(c => c + 1);
});
}
return (
<div>
{isPending && <Spinner />}
<button onClick={handleClick}>{count}</button>
</div>
);
}
Hinweis:
Aktualisierungen in einer Transitions-Phase führen zu dringlicheren Aktualisierungen wie etwa Klicks.
Bei Aktualisierungen in Transitionen wird kein Fallback für wieder ausgesetzte Inhalte angezeigt. Dadurch kann der Benutzer weiterhin mit dem aktuellen Inhalt interagieren, während die Aktualisierung gerendert wird.
useId
const id = useId();
useId
ist ein Hook für die Erzeugung eindeutiger IDs, die auf dem Server und dem Client stabil sind, während sie gleichzeitig Hydrationsabweichungen vermeiden.
Hinweis
useId
dient nicht zum Erzeugen von Keys in einer Liste. Keys sollten aus den Daten generiert werden.
In diesem einfachen Beispiel wird die id
direkt an diejenigen Elemente übergeben, die sie benötigen:
function Checkbox() {
const id = useId();
return (
<>
<label htmlFor={id}>Magst du React?</label>
<input id={id} type="checkbox" name="react"/>
</>
);
};
Bei mehreren IDs in derselben Komponente kann man ein Suffix mit derselben id
anhängen:
function NameFields() {
const id = useId();
return (
<div>
<label htmlFor={id + '-firstName'}>Vorname</label>
<div>
<input id={id + '-firstName'} type="text" />
</div>
<label htmlFor={id + '-lastName'}>Nachname</label>
<div>
<input id={id + '-lastName'} type="text" />
</div>
</div>
);
}
Hinweis:
useId
erzeugt eine Zeichenfolge, die das Token ”:” enthält. Dies hilft sicherzustellen, dass das Token eindeutig ist, wird aber in CSS-Selektoren oder APIs wiequerySelectorAll
nicht unterstützt.
useId
unterstützt einenidentifierPrefix
, um Kollisionen in Anwendungen mit mehreren Roots zu verhindern. Zur Konfiguration siehe die Optionen fürhydrateRoot
undReactDOMServer
.
Library Hooks
Die folgenden Hooks sind für Autoren von Libraries vorgesehen, um diese tief in das React-Modell zu integrieren, und werden normalerweise nicht im Anwendungscode verwendet.
useSyncExternalStore
const state = useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot]);
useSyncExternalStore
ist ein Hook, der für das Lesen und Subscriben von externen Datenquellen empfohlen wird, und zwar in einer Weise, die mit gleichzeitigen Rendering-Funktionen wie selektiver Hydration und Time-Slicing kompatibel ist.
Diese Methode gibt den Wert des Speichers (engl. store) zurück und nimmt drei Argumente entgegen:
subscribe
: Funktion, um einen Callback zu registrieren, der immer dann aufgerufen wird, wenn sich der Speicher ändert.getSnapshot
: Funktion, die den aktuellen Wert des Speichers zurückgibt.getServerSnapshot
: Funktion, die den beim Server-Rendering verwendeten Snapshot zurückgibt.
Das einfachste Beispiel ist das Subscriben des gesamten Speichers:
const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
Man kann aber auch ein bestimmtes Feld abonnieren:
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
);
Beim serverseitigen Rendering muss man den auf dem Server verwendeten Speicherwert serialisieren und an useSyncExternalStore
übergeben. React verwendet diesen Snapshot während der Hydration, um serverseitige Fehlanpassungen zu vermeiden:
const selectedField = useSyncExternalStore(
store.subscribe,
() => store.getSnapshot().selectedField,
() => INITIAL_SERVER_SNAPSHOT.selectedField,
);
Hinweis:
getSnapshot
muss einen zwischengespeicherten Wert zurückgeben. Wenn getSnapshot mehrmals hintereinander aufgerufen wird, muss es genau denselben Wert zurückgeben, es sei denn, es wurde zwischendurch eine Speicheraktualisierung vorgenommen.Für die Unterstützung mehrerer React-Versionen wird ein Verbindungsstück (engl. shim) zur Verfügung gestellt, der als
use-sync-external-store/shim
veröffentlicht wird. Dieses Verbindungsstück wirduseSyncExternalStore
bevorzugen, wenn es verfügbar ist, und auf eine User-Space-Implementierung zurückgreifen, wenn es nicht verfügbar ist.Zur Vereinfachung bieten wir auch eine Version der API mit automatischer Unterstützung für die Memoisierung des Ergebnisses von getSnapshot, das als
use-sync-external-store/with-selector
veröffentlicht wird.
useInsertionEffect
useInsertionEffect(didUpdate);
Die Signatur dieses Hooks ist identisch mit useEffect
, aber er feuert synchron vor allen DOM-Mutationen. Verwende ihn, um Styling in das DOM zu injizieren, bevor das Layout in useLayoutEffect
gelesen wird. Da der Geltungsbereich dieses Hooks begrenzt ist, hat er keinen Zugriff auf refs und kann keine Aktualisierungen planen.
Hinweis:
useInsertionEffect
sollte beschränkt sein auf Autoren von CSS-in-JS-Libraries. Ziehe ihm stattdessenuseEffect
oderuseLayoutEffect
vor.