Context

Context

Möglichkeit, Werte aus einer Komponente direkt allen weiter unten im Dokumentenbaum liegenden Komponenten zur Verfügung zu stellen - ohne diese über jede Ebene übergeben zu müssen

Das Interface von Context kann sowohl Daten (aus dem State) als auch Eventhandler übergeben.

Context

eine Anwendung kann viele verschiedene Kontexttypen haben, z.B.:

  • ThemeContext
  • LanguageContext
  • UserContext
  • TodosContext
  • ...

Context

eine Komponente weiter oben im Komponentenbaum kann ein Provider eines Kontexts sein

eine Komponente weiter unten im Komponentenbaum kann ein Consumer sein

(Datenfluss von oben nach unten, aber mit übersprungenen Zwischenebenen)

Context

mögliche Struktur mit Providern, die selbst State verwalten:

  • LanguageProvider (Verwalten / Bereitstellen von Language State)
    • ThemeProvider (Verwalten / Bereitstellen von Theme State)
      • TodosProvider
        • App
          • TodoList
            • TodoItem
              • ...

Context

Unterscheidung von Providern:

  • "reine Provider" - erhalten Daten via Props, hat keinen internen State
  • Provider mit State - haben internen State, verwenden einen "reinen Provider", um diesen zur Verfügung zu stellen
    • können "manuell" definiert werden
    • können mittels der Library constate definiert werden

Context und State via Constate

Constate

constate: Library, die einen Kontext mit zugehörigem State generieren kann

Constate

Definieren des Context:

selbst definierter Hook, der Todo-Daten verwaltet:

function useTodos() {
  // ...
  return { todos, addTodo, deleteTodo, setTodoCompleted };
}

erstellen einer Provider-Komponente und eines Consumer-Hooks:

const [TodosProvider, useTodosContext] = constate(useTodos);

Constate

"Providen" des Contexts:

function App() {
  return (
    <TodosProvider>
      <AddTodoForm />
      <TodoList />
      <Statistics />
    </TodosProvider>
  );
}

Constate

Abfragen des Context:

function TodoList() {
  const {
    todos,
    deleteTodo,
    setTodoCompleted,
  } = useTodosContext();
  // ...
}

Context mit reinem React

Context

Schritte, um Context zur Verfügung zu stellen:

  • Context definieren (Typ und Standardwerte)
  • eventuell: Provider-Komponente mit State "versehen"
  • Provider-Komponente in der Komponentenhierarchie einbinden

Schritte, um Context abzufragen:

  • Aufrufen von useContext in einer Komponente

Context-Definition

Context-Definition in JavaScript:

// ThemeContext.js

import { createContext } from 'react';

// default value: null
const ThemeContext = createContext(null);

export { ThemeContext };

Standardwert

Ein Context hat immer einen Standard-/Fallback-Wert; dieser wird genutzt, wenn kein passender Provider gefunden wird

In TypeScript: Erstellen des Standard-Werts um den Typechecker zufrieden zu stellen kann mühsam sein

Standardwert

Definieren eines Context-Typs in TypeScript:

type ThemeContextType = {
  theme: string;
  onThemeChange: (theme: string) => void;
};

Standardwert

um den Typechecker zufrieden zu stellen:

tatsächliches Bereitstellen eines Standard-Werts:

const ThemeContext = createContext<ThemeContextType>({
  theme: 'light',
  onThemeChange: () => {},
});

verwenden von null und Cast auf any:

const ThemeContext = createContext<ThemeContextType>(
  null as any
);

mehr Informationen / Lösungen: React TypeScript cheatsheets

Context mit "reinen Providern"

Beispiel: verwenden eines "reinen Providers" (State liegt in der App-Komponente)

function App() {
  const [theme, setTheme] = useState('light');
  return (
    <ThemeContext.Provider
      value={{ theme: theme, onThemeChange: setTheme }}
    >
      ... sub-components ...
    </ThemeContext.Provider>
  );
}

Context mit "reinen Providern"

Beispiel: Produkt-Seite mit einem "reinen" Context-Provider

function ProductPage() {
  // ... (load product data from an API)

  return (
    <ProductContext.Provider value={productData}>
      <ProductDescription />
      <ProductPictures />
      <ProductReviews />
      <ProductQuestionsAndAnswers />
    </ProductContext.Provider>
  );
}

Context mit State

Beispiel: Erstellen eines Providers mit State, der State verwaltet und bereitstellt:

// TodosContext.tsx
function TodosProvider(props: { children: ReactNode }) {
  const todosCtrl = useTodos();
  <TodosContext.Provider value={todosCtrl}>
    {props.children}
  </TodosContext.Provider>;
}
function TodoApp() {
  return <TodosProvider>...</TodosProvider>;
}

Context

Context aus einer Komponente heraus abfragen:

const todosContext = useContext(TodosContext);