30.6.2021 |

React Context

Stable seit React 16.3.0

Die Context API von React ermöglicht Entwicklern, den globalen Anwendungsstatus zu verwalten, ohne ein vollständiges State-Management-System zu benötigen.

Daten, die in tief verschachtelten Komponenten verwendet werden, die nicht dieselbe übergeordnete Komponente haben, sind ein guter Anwendungsfall für den useContext-Hook.

Das Speichern dieser Daten mit useContext erspart Entwicklern das Prop-Drilling, ein Anti-Pattern, das große Datenmengen von übergeordneten Komponenten an tief verschachtelte Komponenten und alle dazwischen liegenden Komponenten weitergibt.

Beispiel-Anwendungsfälle: Daten von aktuell authentifizierten Benutzer, Theming oder bevorzugten Sprache weitergeben.

App.tsx

import React, { createContext, useState } from "react";
import "./App.css";
import ComponentA from "./ComponentA";
import { ThemeContext, themes } from "./theme.context";
import ThemedButton from "./ThemedButton";

export interface CounterContextProps {
  counter: number;
  toggleCounter: () => void;
}

export const CounterContext = createContext<Partial<CounterContextProps>>({});

function App() {
  const [counter, setCounter] = useState(0);
  const [currentTheme, setCurrentTheme] = useState(themes.dark);

  const toggleCounter = () => setCounter((counter) => counter + 1);

  const toggleTheme = () => {
    currentTheme === themes.light
      ? setCurrentTheme(themes.dark)
      : setCurrentTheme(themes.light);
  };

  return (
    <CounterContext.Provider value={{ counter, toggleCounter }}>
      <div className="App">
        <header className="App-header"></header>
        <button onClick={() => toggleCounter()}>
          Toggle Counter From Parent
        </button>
        <h1>Counter Parent: {counter}</h1>
        <ComponentA />
        <ThemeContext.Provider value={currentTheme}>
          <ThemedButton onClick={toggleTheme} />
        </ThemeContext.Provider>
      </div>
    </CounterContext.Provider>
  );
}

export default App;

ComponentA.tsx

// import { useContext } from "react";
import React from "react";
import { CounterContext } from "./App";
import ComponentB from "./ComponentB";

function ComponentA() {
  /* const { counter, toggleCounter } = useContext(CounterContext); */

  return (
    <CounterContext.Consumer>
      {({ counter, toggleCounter }) => {
        return (
          <>
            <button onClick={toggleCounter}>Toggle Counter From A</button>
            <h1>Counter A: {counter}</h1>
            <ComponentB />
          </>
        );
      }}
    </CounterContext.Consumer>
  );
}

export default ComponentA;

ComponentB.tsx

import { useContext } from "react";
import { CounterContext } from "./App";

function ComponentB() {
  const { counter, toggleCounter } = useContext(CounterContext);

  return (
    <>
      <button onClick={toggleCounter}>Toggle Counter From B</button>
      <h1>Counter B: {counter}</h1>
    </>
  );
}

export default ComponentB;

theme.context.ts

import { createContext } from "react";

export const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee",
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222",
  },
};

export const ThemeContext = createContext(themes.dark);

ThemedButton.tsx

import { useContext } from "react";
import { ThemeContext } from "./theme.context";

interface Props {
  onClick: () => void;
}

function ThemedButton({ onClick }: Props) {
  const theme = useContext(ThemeContext);

  return (
    <button
      onClick={onClick}
      style={{ backgroundColor: theme.background, color: theme.foreground }}
    >
      Themed Button
    </button>
  );
}

export default ThemedButton;
Zur Übersicht

Mehr vom Devsquad...

Patrick Schaper

Evolutionsstrategien

Jan Sauer

Developing inside a Container