
Als Front-End- oder Full-Stack-Entwickler stößt vermutlich jeder irgendwann auf ein Projekt, bei dem mehrere Plattformen entwickelt werden müssen, wie z.B. bei Web und Mobile. Bis vor Kurzem hätten Sie dabei die Wahl gehabt, mindestens drei verschiedene Anwendungen zu entwickeln, eine für Web, eine für Android und eine für iOS. In diesem Beitrag widmen wir uns der Anwendung React Native.
Erfreulicherweise gibt es inzwischen einige Initiativen, die versuchen, den Code zwischen verschiedenen Plattformen zu vereinheitlichen. Eine der prominentesten ist React Native.
React Native
React Native vereinheitlicht die Entwicklung mobiler Anwendungen. Das bedeutet, dass es genügt, eine einzige Anwendung sowohl für Android als auch für iOS zu entwickeln. Es gibt auch ein Projekt, das die Entwicklung für Windows 10 ermöglicht.
Wenn es um Codesharing geht, ist der Web-Anteil allerdings noch immer isoliert. Wie Sie sich anhand der Namen vorstellen können, haben React und React Native viele Gemeinsamkeiten, die eine Art Austausch von Code zwischen Mobile- und individueller Webentwicklung ermöglichen. Der erste Schritt zum Verständnis von Codesharing besteht darin, die Gemeinsamkeiten zu verstehen. Übrigens ist das Motto von React „Einmal lernen, überall schreiben“, wie man an der Notwendigkeit eines solchen Beitrags erkennen kann, nicht ganz richtig.
React und React Native im Vergleich
Code in React und React Native zu schreiben ist ziemlich ähnlich. Der grundlegende Unterschied besteht darin, dass man in React HTML-Elemente rendert, während man in React Native stattdessen vordefinierte Komponenten rendert, die aus der React Native-Bibliothek importiert wurden. Die Liste der Komponenten können Sie auf der React Native-Website einsehen.
In der folgenden Abbildung sehen Sie einen Vergleich zweier Komponenten, eine für React und die andere für React Native, die versuchen, die gleiche Funktionalität zu erreichen. Man kann leicht Analogien zwischen den von jeder Komponente verwendeten Komponenten erkennen, wie z.B. die Äquivalenz zwischen <div> und <view> Elementen.


Ein weiterer Unterschied ist die Art und Weise, wie die Komponenten mit CSS umgehen. React ist flexibler und bietet die Möglichkeit, CSS auf verschiedene Art und Weise zu handhaben und CSS-Präprozessoren zu verwenden. React Native hat wiederum einige starre Regeln, wenn es um das Styling der Komponenten geht.
Hier bieten sich Ihnen einige Möglichkeiten, CSS in React zu stylen.
Mit classNames, die mit Sass, Less oder jedem anderen CSS-Präprozessor kombiniert werden können:


Mit Inline-Styling, das direkt in den Elementen selbst erreicht werden kann, wie in der Abbildung unten.

Oder isoliert in ein separates Objekt oder sogar in eine Datei.

Additionally, you could use libraries such as Styled Components to enhance the usage of styling in React.
Bei React Native besteht jedoch nicht die Möglichkeit, mittels ClassNames und CSS-Präprozessoren zu stylen. Stattdessen können wir Inline-Styles direkt in den Komponenten verwenden oder besser: die Funktion Stylesheet.create() nutzen und die Objekte wie im Bild gezeigt übergeben:

Außerdem ist die für React erwähnte Stilkomponenten-Bibliothek auch für React Native verfügbar.
Wie man Code teilt
Nun zum wichtigen Teil: Wie können wir den Code teilen? In den Beispielen haben Sie vielleicht schon erkannt, dass die Logik beider Komponenten sowie der Code für diese Logik genau gleich ist. Warum also zweimal schreiben?
Hier ein Beispiel dafür, wie Code geteilt werden kann, indem die Logik in eine Komponente aufgeteilt wird und zwei spezialisierte Komponenten für die visuellen Teile jeder Anwendung vorhanden sind.



Aus den obigen Bildern wird deutlich, dass wir nur eine logische Komponente zusammen mit zwei visuellen Komponenten als Unterobjekte der ersten verwenden können, die entweder Web- oder Anwendungskomponenten rendern, je nachdem, welche Plattform verwendet wird. Dies kann entweder mit Klassen- oder mit Funktionskomponenten geschehen, mit oder ohne Redux. Alles, was die Komponentenlogik betrifft und in React vorhanden ist, wird nämlich auch von React Native akzeptiert.
In diesem Parent-Child-Szenario haben wir einen mächtigen Verbündeten: Babel. Mit Babel kann man die Importfunktion auf die Parent-Komponente anwenden, ohne sich um irgendeine Art von bedingter Verwendung der Komponente kümmern zu müssen. Babel kann automatisch entscheiden, welchen Import Sie für die Elternkomponente verwenden möchten, je nachdem, wie Sie ihr Projekt aufbauen. Dazu können Sie einfach beide Komponenten, Web und Anwendung im selben Ordner mit unterschiedlichen Erweiterungen haben. Eine mit „.js“ (oder „.ts“, wenn Sie TypeScript verwenden), und eine mit „.native.js“ (oder „.native.ts“). Sie können dieses Muster in der übergeordneten Komponente des oben erwähnten Beispiels sehen.

Wenn Sie Hooks verwenden, können Sie die Logik auch in einen benutzerdefinierten Hook trennen und die notwendigen Variablen und Funktionen zurückgeben, die Sie für ihre Logik benötigen. Dieses Verhalten können Sie im Beispiel unten sehen. Hier können Sie mehr über benutzerdefinierte Hooks lesen.



Der Vorteil dieser Methode im Vergleich zur Parent-Child-Methode besteht darin, dass wir nicht darauf angewiesen sind, dass sich die Dateien im gleichen Ordner befinden, damit Babel sie interpretieren kann. Dadurch haben Sie die Möglichkeit, sie ohne Probleme in verschiedenen Repositories zu haben. Das kann für viele Anwendungsfälle recht nützlich sein.
Das Teilen von CSS
Um auf das CSS zurückzukommen, wir haben gesehen, dass React und React Native eine Möglichkeit haben, gemeinsame Styles zu verwenden. Dies geschieht, indem ein Style in einem JSON-Objekt deklariert und in das style-Attribut der Komponenten geladen wird. Um ein gemeinsames Stylesheet zu erreichen, könnten wir die Styles wie in der Abbildung unten verwenden.

Es wäre sogar möglich, das Objekt zu erweitern, um zwei getrennte Styles zu erreichen, die auf einem gemeinsamen geteilten Style basieren. Die gemeinsame Nutzung von Styles ist jedoch etwas, das möglicherweise zu schwer zu pflegen ist und vielleicht sogar mehr Zeit erfordert, als zwei völlig getrennte Style-Definitionen zu verwalten. Wenn Sie eine Vereinheitlichung anstreben, bedenken Sie, dass es ein nicht so lohnender Weg sein könnte.
Anwendungsfall: WordPress hinzufügen
Bei SPRYLAB stellte das Projekt, das wir uns für die gemeinsame Nutzung von Code vorstellten, eine große Herausforderung dar. Unser Kunde wollte die Flexibilität haben, die Komponenten auf seiner Website nach seinem eigenen Willen neu anzuordnen. Daher entschied sich das Team für die Verwendung von WordPress für den Webteil der Anwendung. Das bedeutete, dass es beim Versuch, den Code zu teilen, mehrere Herausforderungen gab.
Momentan verwendet WordPress zum Rendern seiner Widgets React. Jedes Widget wird jedoch separat aus den PHP-Dateien geladen und wie eine separate React-Instanz behandelt. Das bedeutet, dass der Teil der Anwendung, der alle Komponenten vereint, von PHP und nicht von JavaScript behandelt wird. So wären wir nicht in der Lage, einen einzigen Kontext oder Speicher zu haben, um die Zustände zwischen den notwendigen Komponenten zu teilen. Wir sind daher zu dem Schluss gekommen, dass der Teil der Logik, den wir teilen könnten, eine Zwischenebene zwischen einem globalen Zustand und den visuellen Komponenten darstellen würde. Die Zeit, die wir dafür aufwenden müssten, um dies zu bewerkstelligen, wäre jedoch vergleichbar mit der Zeit, die wir für die Erstellung völlig isolierter Logiken aufwenden müssten.
In unserem speziellen Fall haben wir schließlich entschieden, dass es sich nicht lohnte, ganze Komponenten gemeinsam zu nutzen. So blieben wir bei der gemeinsamen Nutzung einiger spezifischer Funktionen, insbesondere derjenigen, die die Backend-API-Aufrufe machten. Wir hatten auch TypeScript-Definitionen, Lokalisierungsdateien, Assets und Konfigurationsfunktionen in unserem gemeinsam genutzten Repository, die wir mit der Option „git+ssh“ für unsere package.json-Dateien problemlos zu jedem der spezifischen Repositories hinzufügten.
Rückblickend wäre es vielleicht möglich gewesen, zusätzliche benutzerdefinierte Funktionen/Hooks zu verwenden, ähnlich dem „Anwendungsbeispiel“, das in einem der obigen Bilder dargestellt ist und diese Funktionen in jedem Teil zu erweitern, wann immer es notwendig ist. Allerdings wären wir immer noch recht eingeschränkt, indem was wir tun könnten.
Nächster Schritt: Den Code vereinheitlichen
Zum Abschluss dieses Blogbeitrags wollen wir neben der gemeinsamen Nutzung von Code auch den einzigen einheitlichen Code ansprechen. Gegenwärtig kann dies mit Bibliotheken wie React Native for Web erreicht werden. Diese ermöglichen das Schreiben eines einzigen React Native-Codes, der für das Web konvertiert wird. Flutter, ein neues Framework von Google, gilt als Antwort auf React Native und soll das Thema unseres nächsten Blogbeitrags sein.






