Provider
Der React Context Provider ist ein zentraler Bestandteil des Context-API-Systems und dient dazu, Daten und Zustände im Komponentenbaum für alle darunterliegenden Komponenten verfügbar zu machen. Er umschließt die Komponenten, die auf den geteilten Kontext zugreifen sollen, und stellt sicher, dass Änderungen am Zustand automatisch und effizient an alle Konsumenten weitergegeben werden. Dadurch lässt sich die Weitergabe von Props durch viele Komponentenebenen hinweg vermeiden, was den Code übersichtlicher und wartbarer macht. React Context Provider ist besonders nützlich für globale Einstellungen, Authentifizierungszustände oder Theme-Informationen, die an verschiedenen Stellen der Anwendung benötigt werden.
Inhaltsverzeichnis
Aufbau
Der Provider ist ein Component, das aus dem Context-Objekt stammt und die Daten für alle untergeordneten Components bereitstellt. Er definiert, welcher Wert im Context verfügbar sein soll.
Syntax
Die Verwendung eines Context-Providers sieht folgendermaßen aus.
<MyContext.Provider value={/* Irgendein Wert */}>
...
</MyContext.Provider>
Das value
Prop ist entscheidend. Es besimmt, welcher Wert an die Komponenten weitergegeben wird, die den Context konsumieren, also Daten aus dem Context auslesen.
Beispiel - einfache Werte
Damit das Thema etwas greifbarer wird, bauen wir ein Beispiel auf, in welchem wir zwei Button-Components definieren. Ein Button-Component wird unseren Context-Provider verwenden und das andere Button-Component wird ohne Context-Provider eingesetzt.
Wir nennen unser Beispiel ThemedButtonExample.jsx
.
// React
import { createContext, useContext, useState } from 'react';
// Context mit einem Startwert
const ThemeContext = createContext('light');
const ThemedButton = () => {
// Verwendung des Context-Objekts
const theme = useContext(ThemeContext);
const buttonStyles = {
color: theme === 'dark' ? '#fffff' : '#00000',
backgroundColor: theme === 'dark' ? '#450373' : 'lightblue'
};
return (
<button className={theme} style={buttonStyles}>
Ein {theme} button
</button>
);
};
const ThemedButtonExample = () => {
// State Definition
const [theme, setTheme] = useState('dark');
return (
<>
<ThemeContext.Provider value={theme}>
<p><ThemedButton /></p>
</ThemeContext.Provider>
<p><ThemedButton /></p>
<button onClick={() => setTheme(current => theme === 'dark' ? 'light' : 'dark')}>
Theme wechseln
</button>
</>
);
};
export default ThemedButtonExample;
Als Ergebnis erhalten wir zwei Buttons. Ein Button kann auf die Werte/Daten des Context-Objektes zugreifen, weil dieser innerhalb des ThemeContext.Provider
platziert ist und der andere Button vom gleichen Component-Typ nicht.
Beim Klick auf den Button “Theme wechseln” sehen wir, dass nur ein Button auf die Aktualisierung des Themes reagiert.


Provider Wrapper
Wenn man komplexere Werte hat und ggf. auch eine Zustandsverwaltung im gleichen Zusammenhang verwenden möchte, besteht die Möglichkeit einen eigenen Provider-Wrapper zu erstellen, welcher dann als tatsächlicher Wrapper um die Components eingesetzt wird.
Dieser eigener Provider-Wrapper gibt aber den tatsächlichen Context-Provider zurück. Im inneren die children
Prop verwendet, um einfach alles zu umgeben, was man an Elementen im CustomProviderWrapper
platziert.
Hier ein schematischer Aufbau.
function CustomProviderWrapper({ children }) {
...
return (
<MyContext.Provider value={value}>
{children}
</MyContext.Provider>
);
}
function App() {
return (
<CustomProviderWrapper>
<Header />
<MainContent />
</CustomProviderWrapper>
);
}
Ein großer Vorteil von diesem Ansatz ist, dass man einige Funktionen und die Zustandsverwaltung innerhalb von diesem eigenen Context-Provider-Wrapper definieren kann. Das hält unsere Components sauber.
Provider Wrapper - Beispiel
Erstellen wir ein Beispiel, indem wir diesen Ansatz verwenden und erproben. Wir nennen unsere Datei CustomProviderWrapper.jsx
.
Wichtiger Part von dieser Datei wird UserProvider
sein. Das ist unser Provider-Wrapper, welcher den Zustand und ein paar Funktionen, welche wir als Wert an das tatsächliche Context-Objetk binden.
// React
import {
createContext,
useContext,
useState
} from 'react';
// Context-Object definieren
const UserContext = createContext();
// Eigener Provider Wrapper
function UserProvider({ children }) {
// State definieren
const [user, setUser] = useState(null);
// Login Funktion
const login = (username) => {
setUser({ name: username, isLoggedIn: false });
};
// Logout Funktion
const logout = () => {
setUser(null);
}
// Inhalt des Context-Objekts
const value = {
user,
login,
logout
};
// Rückgabe des tatsächlichen Providers
return (
<UserContext.Provider value={value}>
{children}
</UserContext>
);
}
// Hilfs-Component (Header)
function Header() {
// Context auslesen/verwenden
const { user, login, logout } = useContext(UserContext);
// Login Button Klick-Event definieren
const onLoginAction = () => {
login('John');
};
// Logout Button Klick-Event definieren
const onLogoutAction = () => {
logout();
};
return (
<header>
<p>
<button onClick={onLoginAction}>
Login
</button>
</p>
<p>
<button onClick={onLogoutAction}>
Logout
</button>
</p>
</header>
);
}
// Hilfs-Component (MainContent)
function MainContent() {
// Context-Objekt auslesen - nur Benutzer
const { user } = useContext(UserContext);
return (
<main>
{user ? (
<>
<p>User: {user.name}</p>
<p>Is logged in: {user.isLoggedIn ? 'Yes' : 'No'}</p>
</>
) : (
<p>Bitte anmelden</p>
)}
</main>
);
}
// Haupt-Component - Verwendung des Provider-Wrappers
function CustomProviderWrapper() {
return (
<UserProvider>
<Header />
<MainContent />
</UserProvider>
);
}
export default CustomProviderWrapper;
Als Ergebnis haben wir zwei Buttons und eine optionale Ausgabe von Benutzerdaten, wenn wir die Aktion “Login” ausführen. Beim “Abmelden” setzt sich der Wert zurück.