Bewege Daten ohne Prop Drilling mithilfe von Context und behalte dabei seine erneuten Renderings und Grenzen im Griff.
Diese Lektion in Kodokon öffnenProp Drilling bezeichnet jene Props, die durch drei oder vier zwischengeschaltete Komponenten gereicht werden, ohne dort verwendet zu werden, nur um ein Blatt des Baums zu erreichen. Jede Schicht, die sie durchqueren, wird an Daten gekoppelt, die sie nicht interessieren. Context löst dieses Transportproblem: createContext erstellt den Kanal, ein Provider veröffentlicht einen Wert, und useContext liest ihn aus jedem Nachfahren. Behalte die Nuance im Kopf: Context transportiert Zustand, er verwaltet ihn nicht - der Wert lebt weiterhin in einer Komponente, hier im Provider.
import { createContext, useMemo, useState } from "react";
const ThemeContext = createContext(null);
function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
const value = useMemo(
() => ({ theme, setTheme }),
[theme]
);
return (
<ThemeContext.Provider value={value}>
{children}
</ThemeContext.Provider>
);
}Wenn sich der Wert des Providers ändert, rendern alle Consumer neu, selbst tief verschachtelte - und React.memo schützt sie nicht, weil es Props vergleicht, nicht Context. Die klassische Falle verschlimmert das Ganze: value={{ theme, setTheme }} zu schreiben erzeugt bei jedem Rendern des Providers ein frisches Objekt, also eine neue Referenz, also kaskadierende erneute Renderings, selbst wenn sich theme nicht bewegt hat. Genau dafür ist das useMemo oben da. Runde das Ganze mit einem Zugriffs-Hook ab, der außerhalb des Providers laut fehlschlägt.
import { useContext } from "react";
function useTheme() {
const context = useContext(ThemeContext);
if (context === null) {
throw new Error(
"useTheme must be inside <ThemeProvider>"
);
}
return context;
}Bevor du einen Context erstellst, schöpfe zuerst die Möglichkeit der Komposition aus. Wenn eine zwischengeschaltete Schicht nichts weiter tut, als eine Prop weiterzureichen, kehre die Struktur um: Baue das Element an der Spitze des Baums, wo die Daten leben, und reiche es über children oder eine dedizierte Prop nach unten. Die zwischengeschaltete Schicht wird generisch und die Daten laufen durch keine Komponente mehr, die sie nicht verwendet.
function App({ currentUser }) {
return (
<Layout
header={<TopBar user={currentUser} />}
content={<Dashboard />}
/>
);
}