React-Komponenten-Zustand (State)

Komponenten können State haben, welcher der private Teil der Komponentendaten ist und zum Verwalten dynamischer Daten verwendet werden kann.

State gilt nur für Klassenkomponenten oder kann bei Verwendung von React Hooks in Funktionskomponenten verwendet werden.

React behandelt Komponenten als Zustandsmaschinen. Durch Interaktion mit Benutzern werden verschiedene Zustände umgesetzt und dann wird die UI gerendert, um die Benutzeroberfläche mit den Daten konsistent zu halten.

In React müssen Sie nur den State der Komponente aktualisieren und dann die Benutzeroberfläche basierend auf dem neuen State neu rendern (das DOM nicht manipulieren).

Das folgende Beispiel erstellt eine ES6-Klasse, die React.Component erweitert, und verwendet this.state in der render()-Methode, um die aktuelle Uhrzeit zu ändern.

Fügen Sie einen Klassenkonstruktor hinzu, um den State this.state zu initialisieren. Klassenkomponenten sollten immer den Basiskonstruktor mit props aufrufen.


State-Verwaltung in Klassenkomponenten

Erstellen Sie eine zustandsbehaftete Klassenkomponente:

Counter.js-Datei

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  increment = () => {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Zähler: {this.state.count}</p>
        <button onClick={this.increment}>Erhöhen</button>
      </div>
    );
  }
}

export default Counter;

Rendern Sie die Komponente in src/index.js:

Beispiel

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Counter-Komponente rendern
root.render(<Counter />);

State-Management in Funktionskomponenten (mit Hooks)

Mit React Hooks kann State in Funktionskomponenten verwendet werden. Der am häufigsten verwendete Hook ist useState.

Eine zustandsbehaftete Funktionskomponente erstellen:

Counter.js-Datei

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Anzahl: {count}</p>
      <button onClick={() => setCount(count + 1)}>Erhöhen</button>
    </div>
  );
}

export default Counter;

Rendern Sie die Komponente in src/index.js:

Beispiel

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Counter from './Counter';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Counter-Komponente rendern
root.render(<Counter />);

Beispiel

Ein Clock-Beispiel erstellen, um den Komponenten-State zu verstehen:

React-Beispiel

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hallo, Welt!</h1> <h2>Es ist{this.state.date.toLocaleTimeString()}.</h2> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Clock /> );

Ausprobieren »

Als Nächstes lassen wir die Clock ihren eigenen Timer einrichten und sich jede Sekunde aktualisieren.

Hinzufügen von Lifecycle-Methoden zur Klasse

In Anwendungen mit vielen Komponenten ist es sehr wichtig, Ressourcen freizugeben, die von Komponenten belegt werden, wenn sie zerstört werden.

Immer wenn die Clock-Komponente zum ersten Mal in das DOM geladen wird, möchten wir einen Timer einrichten. Dies wird in ReactMounting genannt.。

Ebenso möchten wir, wenn das von Clock erzeugte DOM entfernt wird, auch den Timer löschen. Dies wird in ReactUnmounting genannt.。

Wir können spezielle Methoden in der Komponentenklasse deklarieren, um etwas Code auszuführen, wenn die Komponente gemountet oder unmounted wird:

React-Beispiel

class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hallo, Welt!</h1> <h2>Es ist{this.state.date.toLocaleTimeString()}.</h2> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Clock /> );

Ausprobieren »

Beispielanalyse:

componentDidMount()undcomponentWillUnmount()Diese Methoden werden Lifecycle-Hooks genannt.

Nachdem die Komponentenausgabe in das DOM gerendert wurde, wird dercomponentDidMount()-Hook ausgeführt, und wir können in diesem Hook einen Timer einrichten.

this.timerID ist die ID des Timers, und wir könnencomponentWillUnmount()den Timer im Hook löschen.

Reihenfolge der Codeausführung:

  1. Wann<Clock />wird übergebenReactDOM.render(), React ruftClockden Konstruktor der Komponente. DaClockdie aktuelle Zeit anzeigen muss, initialisiert sie sich mit einem Objekt, das die aktuelle Zeit enthältthis.state. Diesen State werden wir später aktualisieren.

  2. React ruft dannClockder Komponenterender()Methode. Auf diese Weise weiß React, was auf dem Bildschirm angezeigt werden soll, und dann aktualisiert React das DOM entsprechend.Clockdie Render-Ausgabe von

  3. WannClockWenn die Ausgabe von in das DOM eingefügt wird, ruft ReactcomponentDidMount()den Lifecycle-Hook. DarinClockdie Komponente bittet den Browser, einen Timer einzurichten, der einmal pro Sekunde aufgerufen wirdtick()。

  4. Der Browser ruft dietick()Methode jede Sekunde. Darin,Clockdie Komponente aufruftsetState()mit einem Objekt, das die aktuelle Zeit enthält, um eine UI-Aktualisierung zu planen. Durch den Aufruf vonsetState(), weiß React, dass sich der Zustand geändert hat, und ruftrender()erneut auf, um zu bestimmen, was auf dem Bildschirm angezeigt werden soll. Diesmal,render()in der Methode,this.state.datewird anders sein, sodass die Render-Ausgabe die aktualisierte Zeit enthält und das DOM entsprechend aktualisiert wird.

  5. Sobald dieClockKomponente aus dem DOM entfernt wird, ruft ReactcomponentWillUnmount()diese Hook-Funktion, und der Timer wird gelöscht.

Daten fließen von oben nach unten

Weder übergeordnete noch untergeordnete Komponenten können wissen, ob eine Komponente zustandsbehaftet oder zustandslos ist, und es sollte ihnen egal sein, ob eine Komponente als Funktion oder als Klasse definiert ist.

Deshalb wird State oft als lokal oder gekapselt bezeichnet. Keine anderen Komponenten können darauf zugreifen, außer der Komponente, die ihn besitzt und setzt.

Im folgenden Beispiel erhält die Komponente FormattedDate den Datumswert in ihren Props und weiß nicht, ob er aus dem State von Clock, aus den Props von Clock oder aus einer manuellen Eingabe stammt:

React-Beispiel

function FormattedDate(props) { return <h2>Es ist{props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hallo, Welt!</h1> <FormattedDate date={this.state.date} /> </div> ); } } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <Uhr /> );

Ausprobieren »

Dies wird oft als Top-down- oder Einweg-Datenfluss bezeichnet. Jeder State gehört immer einer bestimmten Komponente, und alle Daten oder UI, die von diesem State abgeleitet werden, können nur Komponenten beeinflussen, die im Baum darunter liegen.

Wenn du dir einen Komponentenbaum als einen Wasserfall aus Props vorstellst, ist der State jeder Komponente wie eine zusätzliche Wasserquelle, die an einer beliebigen Stelle hinzukommt, aber ebenfalls nach unten fließt.

Um zu zeigen, dass alle Komponenten wirklich isoliert sind, können wir eine App-Komponente erstellen, die drei Clock-Komponenten rendert:

React-Beispiel

function FormattedDate(props) { return <h2>Es ist{props.date.toLocaleTimeString()}.</h2>; } class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hallo, Welt!</h1> <FormattedDate date={this.state.date} /> </div> ); } } function App() { return ( <div> <Clock /> <Clock /> <Clock /> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />);

Ausprobieren »

Im obigen Beispiel richtet jede Clock-Komponente ihren eigenen Timer ein und aktualisiert sich unabhängig.

In React-Anwendungen wird die Frage, ob eine Komponente zustandsbehaftet oder zustandslos ist, als Implementierungsdetail der Komponente betrachtet, das sich im Laufe der Zeit ändern kann.

Wir können zustandslose Komponenten innerhalb zustandsbehafteter Komponenten verwenden, und wir können auch zustandsbehaftete Komponenten innerhalb zustandsloser Komponenten verwenden.

Andere Erweiterungen