JavaScript

Kolumne: Olis bunte Welt der IT

React – Mal was anderes als Angular
1 Kommentar

Alle benutzen heute Angular, oder? So scheint es manchmal, wenn man sich bei Konferenzen umschaut oder auch in bestimmten Kreisen umhört. Allerdings sieht die Wahrheit ganz anders aus: Seit Monaten sind die Downloadzahlen für React mehr als fünfmal so groß wie die für Angular, und wesentlich größer sind sie schon seit Jahren (Quelle: npmtrends.com).

Wenn man noch die Zahlen für verwandte Pakete wie react-native oder die für alternative Implementationen wie Preact einrechnet, ist der Unterschied noch viel größer. Selbst Vue – eine Library, die konzeptionell stark in Richtung React tendiert – hat jetzt mehr Downloads als Angular.

Ich denke, es ist Zeit, sich mit React zumindest oberflächlich zu beschäftigen, wenn das bisher unterlassen wurde. Sie kennen mittlerweile meine Einstellung zur Entscheidungsfindung: Wenn ich mich gegen etwas entscheide, sollte ich wissen, warum. Wenn ich mich für etwas entscheide, möchte ich zumindest eine Alternative evaluiert haben. Ganz einfach und logisch, oder?

Ein Vorbehalt gegen React, der in der Vergangenheit nicht von der Hand zu weisen war, bezog sich auf die Lizenzierung. Facebook hatte nämlich unangenehme Klauseln zur Standard-BSD-Lizenz hinzugefügt, die manch potenzieller Anwender von React problematisch fand. Details hierzu sind heute nicht mehr relevant, da React seit September 2017 mit einer ganz normalen MIT-Lizenz verfügbar ist.

Den Vergleich mit Angular möchte ich im Folgenden nicht weiter betreiben. Dazu gibt’s online viel zu lesen, aber letztlich hinkt ein solcher Vergleich deutlich aufgrund der unterschiedlichen Ansprüche der Basispakete Angular und React. Angular kann viel, tut viel und ist auch in einfachen Fällen ordentlich komplex – React ist klein (sehr klein mit Preact – 3 KB!), bietet ein Kernmodell und überlässt weitere Funktionalität anderen Libraries. Für den Angular-Neuling besteht eine umfangreiche Aufgabe darin, das System zu kennenzulernen und zu verstehen, und Fehler sind leicht gemacht, wenn eigene Funktionalität auf „falsche“ Weise eingebunden wird. Der React-Neuling hingegen steht vor der Herausforderung, nach einem schnellen Einstieg aus der Vielfalt der verfügbaren Libraries diejenigen herauszufiltern, die Mehrwert für den eigenen Anwendungsfall versprechen.

Der Einstieg

Nun kann es losgehen. Grundsätzlich ist zu empfehlen, ein neues Projekt mithilfe des Tools create-react-app zu erzeugen. Das Tool selbst kann mit npm oder yarn installiert werden. Also etwa so:

npm install -g create-react-app
create-react-app react-test1

Die erzeugte Struktur ist nicht besonders kompliziert, kann aber schon recht viel. Im neuen Projektverzeichnis kann mit yarn start (oder npm start) ein Entwicklungsserver gestartet werden, oder ein Test Runner mit yarn test. Tests sind exemplarisch im Projekt enthalten, wie auch Stylesheets sowie eine Implementation für einen Service Worker. Im Readme des Projekts finden sich Anleitungen zur Integration mit vielen optionalen Systemen, IDEs und Modulen.

Der Democode im neuen Projekt ist nur 29 Zeilen lang, in zwei Dateien – das ist überschaubar und zum Kennenlernen gerade richtig. Es gibt nur drei wirklich wichtige Elemente: einen Platzhalter in index.html, die Komponente App in App.js und eine Zeile in index.js, in die mithilfe von ReactDom.render() die Komponente anstelle des Platzhalters eingesetzt wird.

Wenn Sie sich die Komponente ansehen, stellen Sie schnell fest, dass die verwendete Syntax ungewöhnlich erscheint. Dort finden sich Elemente im JavaScript-Code, die mehr wie HTML aussehen:

render() {
  return (
    <div className="App">
      ...
      <img src={logo} />
      <h1 ...>Welcome to React</h1>
    </div>
  );
}

Diese Syntaxerweiterungen werden JSX genannt. Es handelt sich hier gewissermaßen um einen Compilertrick: Um aus JavaScript heraus auf einfache Weise DOM-Elemente erzeugen zu können, werden Tags, also Elemente in spitzen Klammern, direkt eingebettet. Diese Syntax wird von einem JSX-Compiler – typischerweise einem Babel-Plug-in – in API-Aufrufe (an React.createElement(…)) umgewandelt. Aus dieser Beschreibung sollte deutlich werden, dass man auch ohne JSX für React programmieren kann – die Syntax ist dann allerdings wesentlich komplexer.

Sie können dem Beispiel entnehmen, dass in einem JSX-Block Elemente aus JavaScript eingebettet werden können, indem geschwungene Klammern verwendet werden. Diese Ausdrücke dürfen komplexer sein als im Beispiel – natürlich ist dabei Vorsicht geboten, wie bei jeder ähnlichen Syntax. Kombinationen sind allerdings beinahe beliebig möglich:

render() {
  return (
    <div>
      <p>Some text here</p>
      { isImportant && <div className="important">Important!</div> }
      <p>It is now { showTime ? new Date().toLocaleTimeString() : 'late' }.</p>
    </div>
  )
}

Komponenten sind die Bausteine, aus denen eine React-Anwendung zusammengesetzt wird. Eine Komponente muss sich selbst darstellen können und typischerweise kann sie auch Informationen aus ihrem Kontext übernehmen und anzeigen oder verarbeiten.

Die Komponente App ist als Klasse implementiert. Da sie lediglich eine Methode render enthält (diese dient, wie erwähnt, zur visuellen Darstellung der Komponente), könnte stattdessen auch eine (anonyme) Funktion verwendet werden:

const App = () => <div className="App">...</div>;

Diese Funktion übernimmt die Rolle der Funktion render in der Klassenimplementation. Natürlich bietet die Klasse einen einfacheren Weg, zusätzliche Methoden oder Zustandsdaten zu halten. Allerdings ist React vollständig als funktionales Konzept verwendbar und entsprechende Ansätze sind bereits bei der Erzeugung von Komponenten zu finden.

Eigenschaften für Komponenten

Damit Komponenten dynamisch sein können, muss es möglich sein, ihnen Informationen von außen zu übergeben. Das geschieht primär durch props, eine Kurzform des Worts „Properties“, also Eigenschaften. Für funktionale Komponenten werden props als Parameter empfangen, bei Klassen über this.

const Greeter = props => <div>Hi {props.name}</div>;

class Greeter2 extends Component {
  render() {
    return <div>Hi {this.props.name}</div>;
  }
}

Um Werte an props zu übergeben, werden Attribute im Tag verwendet:

<Greeter name="Oli" />

Aus dieser Syntax können Sie auch entnehmen, dass zur Verwendung einer Komponente keine besondere Methode notwendig ist – diese werden einfach als Elemente in JSX verwendet.

Ein paar Worte zu Updates: React ist generell sehr effizient bei der Umsetzung von Updates an Komponenten, indem (kurz gesagt) nach jedem Rendering der DOM-Baum mit dem vorherigen Stand verglichen wird und nur tatsächlich geänderte Teile aktualisiert werden. Außerdem wird von React sorgfältig selektiert, welche Komponenten überhaupt neu gerendert werden müssen. Zu diesem Thema gibt es noch wesentlich mehr zu sagen, aber der wichtigste Punkt ist, dass diese Entscheidung anhand der props einer Komponente getroffen wird: Wenn sich die props, die im JSX an die Komponente übergeben werden, geändert haben, wird angenommen, dass die Komponente neu gerendert werden muss. Wenn die Werte dieselben sind wie bei einem vorherigen Durchgang, muss render() nicht aufgerufen werden. Mit anderen Worten: Die Funktion, die eine Komponente rendert, muss funktional „pur“ sein, also ohne funktionale Nebeneffekte. Sie dürfen in render keine Werte ändern, besonders nicht die props, oder auf andere Weise Nebeneffekte auslösen.

Wenn’s mehr Status sein darf

Manchmal müssen Komponenten eigene Statusdaten speichern, zusätzlich zu denen, die über props übergeben werden. Diese Daten werden als state bezeichnet. Im Konstruktor der Klasse darf die Variable state einmal explizit gesetzt werden, danach muss sie durch Aufrufe an die Funktion setState modifiziert werden.

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

  render() {
    return (
      <div>
        <p>Value: {this.state.value}</p>
        <button onClick={() => this.setState({ value: 3 })}>Set 3</button>
        <button onClick={() => this.setState({ value: 11 })}>Set 11</button>
      </div>
    );
  }
}

setState sorgt dafür, dass die Komponente neu gerendert wird. Es ist zu beachten, dass dies asynchron geschieht und eventuell mehrere state-Updates zusammengeführt werden, bevor ein neuer Aufruf an render() stattfindet. Wenn Sie sich sorgfältig an funktionale Ideen halten und ohne Nebeneffekte programmieren, sollte das nicht zum Problem werden. Falls Sie im Detail Einfluss auf die Entscheidung nehmen wollen, ob eine Komponenten neu gerendert wird oder nicht, können Sie auch eine der Lifecycle-Methoden verwenden:

class Thing extends Component {
  ...
  shouldComponentUpdate(nextProps, nextState) {
    if (nextState.someValü === this.state.someValü)
      return false;
  }
  ...
}

Eine gute Empfehlung ist, neue Komponenten nicht wie bisher gezeigt von Component abzuleiten, sondern stattdessen die Basisklasse PureComponent zu verwenden. Diese Klasse sorgt dafür, dass render() nur aufgerufen wird, wenn sich entweder props oder state seit dem letzten Aufruf geändert haben. Natürlich gibt es noch immer Fälle, in denen genauere Entscheidungen getroffen werden sollten, aber als Ausgangspunkt ist diese Vorgehensweise recht effizient.

Nun sind mit dieser Beschreibung die Grundlagen von React bereits abgedeckt. Komponenten mit und ohne eigenen Zustand werden zu größeren Komponenten zusammengesetzt und ein Datenfluss „von oben herab“ wird etabliert, indem Werte über props weitergereicht werden. React selbst sorgt für effiziente Rendervorgänge, erlaubt aber dem Programmierer Kontrolle im Detail, wenn Lifecycle-Methoden implementiert werden. Natürlich kann über diese Vorgänge noch viel gesagt werden, aber letztlich deckt die Zusammenfassung alles ab, was React tut.

Neu erfinden ist Zeitverschwendung

Es gibt zahllose Libraries, die mit React zusammenarbeiten und dafür sorgen, dass zur Umsetzung typischer Funktionalität in einer größeren Anwendung nicht dauernd das Rad neu erfunden werden muss. Zunächst empfehle ich für Anhänger der funktionalen Programmierung die Library Recompose. Diese bietet zahlreiche Hilfsfunktionen, die zum Teil als Higher Order Components (HOC) arbeiten, also eine vorhandene Komponentenimplementation kapseln und ihrerseits eine Komponente bereitstellen. Soweit zuvor beschrieben, machte der funktionale Ansatz zur Implementation von Komponenten nur Sinn, wenn sich die Anforderungen auf eine Renderfunktion beschränkten. Mit Recompose können hingegen Komponenten jeglicher Komplexität funktional erzeugt werden.

Für viele Anwendungen empfehle ich außerdem Redux. Diese Library hat sich mittlerweile auch im Angular-Umfeld einen Namen gemacht und dient der zentralen, kontrollierten Zustandsverwaltung. Sie arbeitet hervorragend mit React zusammen und bietet mit Zusatzmodulen wie redux-saga auch für komplexe Systeme mit Hintergrundprozessen leistungsfähige Lösungen. Auch Aspekte wie Lokalisierung lassen sich im Konzept Redux einbinden, wie es etwa das Modul react-localize-redux umsetzt.

Auf der UI-Seite gibt es zahlreiche Libraries, mit denen auf einfache Weise UI-Elemente erzeugt werden können. Ich empfehle besonders, sich react-bootstrap sowie material-ui anzusehen, womit die wichtigsten aktuellen UI-Metaphern abgedeckt werden. Es sprengt den Rahmen dieses Artikels, aber auch react-native soll noch einmal erwähnt werden: eine Umsetzung von React, mit deren Hilfe sich leistungsfähige Mobilanwendungen erzeugen lassen. Natürlich können Mobilgeräte auch mit React selbst versorgt werden, indem HTML/JS als Basis dient. react-native bietet allerdings deutlich bessere Performance, indem native Elemente auf den Mobilplattformen verwendet werden.

Einfach mal ausprobieren!

Wenn Sie nun neugierig sind, machen Sie sich auf den Weg zu einem Onlinespielplatz für React wie z. B. CodeSandbox. Dort können Sie direkt mit React experimentieren und eigene Erfahrungen sammeln. Viel Spaß damit!

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

1 Kommentar auf "React – Mal was anderes als Angular"

avatar
400
  Subscribe  
Benachrichtige mich zu:
Emi
Gast

Ich musste tatsächlich auf das Erscheinungsjahr des Artikels schauen 🙂 Angular hat doch seit den Querelen um das 2er Release ziemlich zu knabbern. So ziemlich der Zeitpunkt des kometenhaften Aufstiegs von React, das jetzt eher Vue.js als „Konkurrenz“ hat als Angular.

X
- Gib Deinen Standort ein -
- or -