Getting started mit React – Teil 1

React wurde 2013 von Facebook als Open-Source-JavaScript-Bibliothek vorgestellt. Das Framework erfreut sich zunehmender Beliebtheit und hat seine Fähigkeiten mehrfach unter Beweis gestellt. Wenig überraschend ist, dass Facebook selbst React nutzt, aber auch andere Größen wie AirBnb oder Instagram laufen mit der JavaScript-Bibliothek.

Der Kern der Bibliothek basiert auf Komponenten-Design: Eine Anwendung wird in möglichst unabhängige, wiederverwendbare Komponenten zerlegt und aus deren Zusammensetzung entsteht letztendlich die Web-Anwendung. Eine Komponente enthält hierbei alle Informationen, um unabhängig zu agieren, das heißt auch der Style (CSS, SASS, LESS) liegt innerhalb einer Komponente. Diese Tatsache kritisieren manche Entwickler an React. Ein wesentlicher Nachteil entsteht daraus aber nicht.

Der große Vorteil von React ist der virtuelle DOM. Dieser stellt den HTML-Teil der Webanwendung im Speicher dar und wird bei jeder Änderung komplett neu gerendert. Der springende Punkt hierbei ist allerdings, dass React den virtuellen DOM benutzt um die tatsächlichen Änderungen im Vergleich zum DOM-Baum im Browser zu erkennen. Nur die geänderten Elemente werden neu gerendert. Dieser Ansatz verhilft React zu einer einwandfreien Performance. Trotz intensiven Änderungen am DOM, während der Laufzeit, können problemlos hoch dynamische Webseiten betrieben werden.

Projekt aufsetzen und erste Schritte

React ist im Kern ja wie gesagt eigentlich nur eine JavaScript-Bibliothek und kann überall, wo JavaScript eingesetzt wird, verwendet werden. In der Regel laufen React Projekte wie alle JavaScript-Projekte ab. In der Praxis kristallisieren sich allerdings einige besondere Vorgehensweisen heraus und es entsteht ein häufig verwendeter Technologie-Stack. Node.JS und npm sind meistens mit von der Partie. Für den Build-Prozess kommen häufig Webpack und Babel zum Einsatz, um eine Anwendung lauffähig machen. Für die Codequalität werden sogenannte Linter eingesetzt, wie ES-Lint oder JS-Lint. Die Linter werden innerhalb des Projekts über eine Config-Datei konfiguriert und unterstützen den Entwickler bei der Einhaltung des Code-Styles, ja zwingen ihn sogar dazu.

Als Entwicklungstool reicht ein Texteditor, es kann aber auch jede andere IDE eingesetzt werden. WebStorm , Sublime und Atom werden immer wieder gern genutzt.

Damit man als Entwickler nicht tagelang damit zubringt, sein Projekt aufzusetzen, gibt es Skripts, die das erledigen. Ein sehr einfaches und effektives Skript wäre z. B. create-react-app. Es kümmert sich genau richtig, nicht zu viel und nicht zu wenig um das Wesentliche. Am Ende hat man ein passendes Projekt, das nicht überladen ist, und die wichtigsten Sachen wie Babel und Webpack sind vorkonfiguriert. In der package.json sind auch schon fertige npm-Kommandos (z. B. zum Starten des Servers) vorhanden. Sollten jemandem die Konfigurationsmöglichkeiten zu eingeschränkt sein, kann man das Projekt auch „ejecten“, dann werden alle embedded-Skripte in den Projektordner kopiert. Dies ist allerdings kein bidirektionaler Vorgang, d. h. einmal „ejectete“ Projekte bleiben wie sie sind.

Will man ein React-Projekt starten, muss man vorher npm und Node.JS installiert haben. Wenn man sich mittels npm das Package „create-react-app“ installiert, kann man es direkt nutzen, um sich eine Projektstruktur erzeugen zu lassen. Für IDEs wie WebStorm, gibt es auch ein Plugin und man kann sich das React-Projekt wie jedes andere anlegen lassen.

Einführung in JSX

Was sich nach einer eigenen Programmiersprache anhört ist eigentlich ein Hybrid aus JavaScript und HTML. In React schreibt man seinen JavaScript- und HTML-Code in eine Datei. Theoretisch könnte man auch den CSS-Code dazu packen, aber eine Trennung von Style und Code sollte wenigstens so weit gehen, dass diese in verschiedenen Dateien landen. JSX wird zu JavaScript-Code transpiliert, ähnlich wie bei Angular 2 und TypeScript. Apropos: Wer TypeScript mag, für den könnte TSX interessant sein, das TypeScript-Pendant zu JSX. Um das Transpilieren muss man sich nicht kümmern, das übernimmt Babel zur Laufzeit.

JSX-Code sieht folgendermaßen aus:

const element = (
  <div>
    <h1>Hello!</h1>
    <h2>Good to see you here.</h2>
  </div>
);

Man muss eigentlich nicht viel dabei verstehen, es reicht, wenn man akzeptiert, dass es HTML jetzt auch innerhalb des JavaScript-Codes gibt, aber es macht die ganze Sache erheblich einfacher, wie wir gleich sehen werden.

Die erste Komponente

Wie bereits zu Anfang erwähnt, basiert React auf Komponenten. Eine Komponente entspricht in der Realität einer JavaScript-Datei und kann natürlich auch innerhalb anderer Komponenten verwendet werden. Um Komponenten zu erstellen, gibt es zwei mögliche Wege. Es gibt die Komponenten-Klassen und die funktionalen Komponenten.

Wir beginnen mit den Komponenten-Klassen:

Komponenten-Klassen

Bevor wir uns an die eigentliche Struktur der React-Klasse machen, erläutern wir kurz, wie eine React Komponente aufgebaut ist. Denn allein mit der Klasse ist es nicht getan, üblicherweise besteht eine Komponente aus folgenden Dateien:

image2017-2-28 14-0-47

  • App.css
    • Enthält die Style Informationen.
  • App.js
    • Enthält den Quellcode (JSX)
  • App.test.js
    • Enthält die Unit-Tests
  • index.js
    • Für den globalen export.

Schauen wir uns den Inhalt der App.js genauer an:

import React, { Component } from 'react';
import './App.css';
 
class App extends Component {
 
    constructor(props) {
        super(props);
    }
     
    componentWillMount(){
         
    }
     
    componentDidMount(){
         
    }
     
    componentWillUnmount(){
         
    }
 
    render() {
        return (
            <div />
        );
    }
}
 
export default App;

Gehen wir den Quellcode einmal durch:

import

Nichts Überraschendes, an dieser Stelle werden die Abhängigkeiten importiert. Das sind in der Regel Libraries oder andere React Komponenten. Die zeile „import React, { Component } from ‚react'“ braucht man immer für eine klassenbasierte Komponente, alles andere ist optional. Die Style-Informationen werden einfach mit einem Import in die Komponente geladen und stehen für den HTML-Teil sofort zur Verfügung.

Klassendeklaration

Wie auch in anderen Programmiersprachen üblich, folgt nun die Klassendeklaration. Wichtig hierbei ist nur der „extends“-Teil. Eine React-Klasse erbt immer von Component.

constructor

Der Konstruktor dient eigentlich nur einem Zweck und zwar der Initialisierung des state. Zu state und props kommen wir aber später. In diesem konkreten Fall ist der Konstruktor überflüssig und dient nur der Veranschaulichung. Wichtig ist aber, dass der Aufruf super(props) immer vorhanden ist und zwar als erste Zeile innerhalb des Konstruktors.

componentWillMount

Dies ist die erste der Lifecycle-Methoden. Diese Methode wird vor der render und vor dem Einhängen im DOM ausgeführt. Die properties stehen zur Verfügung und der Aufruf setState ist erlaubt. Dieser Code wird serverseitig ausgeführt und wird hauptsächlich genutzt, um initialen Code auszuführen.

componentDidMount

Diese Methode wird automatisch nach der render-Methode ausgeführt. Ab hier stehen nun die refs zur Verfügung die setState-Methode löst ein erneutes Rendern aus. Perfekt, um asynchrone Calls auszuführen und die Seite bei Erfolg neu zu rendern.

componentWillUnmount

Der Gegenpart zu componentWillMount wird aufgerufen, unmittelbar bevor die Komponente aus dem DOM entfernt wird. Hier ist der richtige Zeitpunkt um ressourcen wieder freizugeben. Ein erneutes rendern kann hier nicht ausgelöst werden.

render

der wichtigste Teil passiert in der render-Methode. Denn hier wird der HTML-Teil, also das was wir später im Browser sehen, erzeugt.

Der komplette Lebenszyklus lässt sich nun wie folgt zusammenfassen:

constructor >> componentWillMount >> render >> componentDidMount >> componentWillUnmount

Funktionale Komponenten

Die funktionalen Komponenten kommen im Vergleich mit einer Klassen-Komponente mit sehr viel weniger Code aus:

import './App.css';
 
const App = props => (<div />);
 
export default App;

Diese funktionale Komponente liefert genau denselben Effekt wie die klassen basierte und braucht dabei viel weniger Codezeilen. Letztendlich erfüllt sie aber alle Anforderungen einer React Komponente, denn sie bekommt properties als Input und liefert HTML als output. React Komponenten leben von genau diesem Konzept:

Bei funktionalen Komponenten sieht das ganze so aus:

props >> React Komponente >> HTML 

Bei React Klassen hängen dazwischen noch die Lifecycle Methoden

props >> constructor >> componentWillMount >> render >> HTML

Der Unterschied beläuft sich also darauf, dass die funktionalen Komponenten keine Lifecycle-Methoden, sowie keinen state haben.

Deklaration funktionaler Komponenten

Die Deklaration einer funktionalen Komponente wie oben gezeigt, funktioniert nur, wenn im Rumpf direkt der return-Wert eingetragen wird. Also:

const App = props => (<div />);

Der return Wert steht hier in zwischen den ( ). Will man nun aber noch etwas mehr Logik in seiner Komponente unterbringen, dann ändert sich die Syntax leicht:

const App = (props) => {
  
 //your code goes here
 
 return (
    <div />
 );
}

Funktional oder klassenbasiert

Die Entscheidung ist relativ leicht getroffen. Wenn man innerhalb einer Komponente den state oder die Lifecycle Methoden braucht, dann nutzt man Klassen Komponenten. Ansonsten bevorzugt man funktionale Komponenten, da der Quellcode hier meist kürzer und einfacher ist. Außerdem soll in den kommenden React releases besondere Performance Verbesserungen für die funktionalen Komponenten kommen. Daher ist es von Vorteil so viele wie möglich davon zu haben. Derzeit ist der Unterschied in der Produktion nicht zu merken, es könnte aber in naher Zukunft von Vorteil sein wenn man bereits jetzt auf den funktionalen Ansatz setzt.

Properties und State

Zuvor wurden schon mehrfach die Begriffe props und state erwähnt, diesen gehen wir nun näher auf den Grund:

Properties sind Eigenschaften die der Komponente übergeben werden. Entweder im Konstruktor oder als Parameter in funktionalen Komponenten. Die Properties sind als Objekt dann innerhalb der Klasse verfügbar und können verwendet werden, um verschiedene HTML-Ausgaben zu erzeugen oder auch, um die Kommunikation zwischen Komponenten zu ermöglichen. Man kann z. B. über die Properties eine Funktion übergeben, die dann als Callback aufgerufen werden kann und Ereignisse in der Elternklasse auslöst. Properties sind Read-only und somit immutable. Der state wiederum steht nur Klassen-Komponenten zur Verfügung und kann gelesen und beschrieben werden. Eine Änderung im state löst in der Regel einen erneuten Aufruf der render-Methode aus, wodurch der DOM-Baum aktualisiert wird.

Properties definieren

In React definiert man die Properties außerhalb der Komponente:

class App extends Component {
    
    render() {
        return (
            <div />
        );
    }
}
 
App.PropTypes = {
    color: React.propTypes.string.isRequired,
    shape: React.propTypes.object,
}
 
export default App;

Die Syntax ist hierbei relativ einfach: Komponentenname.PropTypes wird ein Objekt zugewiesen. Innerhalb dieses Objekts werden die einzelnen Properties definiert. Die React Type-Syntax wird wie folgt angewandt: React.propTypes.isRequired, der letze Teil (isRequired) ist hierbei optional. Wenn eine Property nicht als required deklariert wird, sollte ein Default-Wert gesetzt werden:

App.defaultProps = {
    shape: 'rectangle',
}
 
App.PropTypes = {
    color: React.propTypes.string.isRequired,
    shape: React.propTypes.string,
}

Sollte eine Property (die nicht den Status required hat) nun den Wert null oder undefined zugewiesen bekommen (das passiert wenn man nichts für diese Property übergibt), dann fällt React automatisch auf die Default-Werte zurück.

Die Properties werden der Komponente im HTML Teil übergeben. Grundsätzlich rendert man in React eine Komponente wie jedes andere DOM-Element:

import React, {Component} from 'react';
import Header from '../Header';
import './App.css';
 
class App extends Component {
 
    render() {
        return (
            <Header tabs="2" orientation="vertical" />
        );
    }
}
 
export default App;

Die Komponente App importiert hier eine andere Komponente names Header, die zwei Properties entgegennimmt: tabs und orientation. Die Properties werden einfach als Attribute im führenden HTML-Tag übergeben und stehen der Header-Komponente unter this.props.tabs bzw. this.props.orientation bei Klassen-Komponenten, oder als props.tabs bei funktionalen Komponenten zur Verfügung.

State in Klassen-Komponenten

Der state ist ein Objekt, das nur Klassen-Komponenten zur Verfügung steht. Der state wird nicht von außen beeinflusst sondern nur von der Komponente selbst. Man kann der Komponente über Callbacks allerdings mitteilen, dass sich der state ändern soll. In der Praxis sieht das wie folgt aus:

class App extends Component {
     
    constructor(props) {
        super(props);
        this.state = {
            color: 'red',
            shape: 'rectangle',
        }
    }
     
    someCallbackFunction (color) {
        this.setState({
            color: color
        });       
    }
 
    render() {
        return (
            <div>
                <Header onCallback={this.someCallbackFunction.bind(this)} />
                <div>
                    selected color: {this.state.color}     
                </div>
            </div>
        );
    }
}

Hier kamen jetzt einige neue Sachen hinzu, die wir der Reihe nach durchgehen. Im Konstruktor wird der state erstmals initialisiert, dabei wird die Struktur des state-Objekts bestimmt, sowie die Default-Werte. Die Funktion someCallback wird an die Komponente Header als Property übergeben und kann dort aufgerufen werden:

class Header extends Component {
 
    onClick() {
        this.props.onCallback('green');
    }
 
    render() {
        return (
            <div>
                <button
                    onClick={this.onClick.bind(this)}
                >
                    Change color to green
                </button>
            </div>
        );
    }
}
 
Header.PropTypes = {
    onCallback: React.propTypes.func.isRequired,
}

Bei einem Klick auf den Button wird nun die lokale Methode onCallback aufgerufen, die wiederum ruft die übergebene Funktion aus der App-Komponente mit dem Parameter green auf. In der App-Komponente wird dann state.color mit dem Aufruf setState auf green gesetzt. Weil sich der state ändert, wird die render-Methode neu ausgeführt und React aktualisiert den DOM im Browser.

Wo vorher in der Zeile selected color: {this.state.color} der Wert red angezeigt wurde, wird nun green angezeigt. Der state wird oft genutzt, um Komponenten ein- bzw. -auszublenden und man setzt ihn innerhalb von Funktionen. Dadurch erreicht man seine Dynamik innerhalb einer Komponente.

„Smarte“ oder „dumme“ Komponenten

Die Bezeichnung Smart Components und Dumb Components sowie Presentional und Container Components werden in React Tutorials häufig verwendet.

Beides meint im Prinzip das gleiche, im folgenden Absatz nutzen wir daher nur die Bezeichnung Smart (Container) und Dumb (Presentional) Components.

Es gibt Komponenten, die smart sind oder als Container fungieren. Diese Komponenten haben in der Regel einen state und beinhalten eine oder mehrere Dumb bzw. Presentional Components. Über den state der Smart Components wird das Verhalten der Applikation gesteuert. Die Dumb Components werden jedes Mal mit veränderten Properties neu gerendert und wissen eigentlich nichts über ihre Elternklassen oder den state. Die Smart Components stellen meistens eine View in der Applikation dar und beinhalten kleinere Komponenten, die je nach state der Applikation unterschiedlich angezeigt werden. Smart Components steuern ihren state selbst und reagieren auf Benutzereingaben. Smart Components werden häufig als Klassen-Komponenten geschrieben, wohingegen die Dumb Components oft funktional daherkommen.

Fazit

React verfolgt einen vielversprechenden Ansatz. Durch die Aufteilung in Komponenten kann innerhalb eines Teams meist unabhängig gearbeitet werden und der Austausch oder die Änderung einzelner Komponenten kann ohne große Mühe erfolgen. Auch können Komponenten leicht wiederverwendet werden und unabhängig gestylt sein. React ist kein kompliziertes Framework sondern eine sehr mächtige JavaScript-Bibliothek. Man muss keine komplizierte Syntax o. ä. lernen, sondern kommt meist mit der EcmaScript-Spezifikation aus. Die Community ist ziemlich groß und es gibt eine Menge vorgefertigter Komponenten, die sich ohne viel Aufwand in ein Projekt einbinden lassen. Die einzige Schwäche ist meiner Meinung nach, dass bei großen Projekten die Kommunikation zwischen den Komponenten schnell einen sehr komplexen Quellcode zur Folge hat. Aber auch dafür gibt es bereits Abhilfe durch Redux bzw. das Flow-Konzept.

Dieser Beitrag wurde unter Software Engineering abgelegt und mit , , , , verschlagwortet. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s