Full-Stack-NLP mit React: Ionic vs. Cordova vs. React Native

Veröffentlicht: 2022-03-11

In den rund 15 Jahren, seit Apple das erste iPhone herausgebracht hat, hat sich die Landschaft der Softwareentwicklung dramatisch verändert. Da Smartphones eine weite Verbreitung finden und an einzigartigen Fähigkeiten zunehmen, ziehen es Benutzer zunehmend vor, über mobile Geräte auf Softwaredienste statt über Desktops oder Laptops zuzugreifen. Smartphones bieten Funktionen wie Geolokalisierung, biometrische Authentifizierung und Bewegungserkennung, von denen viele Desktop-Plattformen erst jetzt zu kopieren beginnen. In einigen demografischen Gruppen ist ein Smartphone oder ein ähnliches mobiles Gerät das primäre Mittel für den Softwarekonsum, wobei Computer vollständig umgangen werden.

Die Unternehmen haben diesen Wandel bemerkt und in erheblichem Maße verstärkt. Mobile Apps sind kein nachträglicher Einfall mehr. Anwendungen, die von Robinhood, einem Finanzvermittlungsunternehmen, über Instagram, ein Social-Media-Unternehmen, bis hin zu Uber, einem Ride-Hailing-Unternehmen, reichen, verfolgen eine Mobile-First-Entwicklungsstrategie. Wenn es eine Desktop-Anwendung gibt, wird diese oft als Ergänzung zur mobilen App angeboten und nicht als Hauptaugenmerk.

Für Full-Stack-Entwickler ist die Anpassung an diese wechselnden Trends von entscheidender Bedeutung. Glücklicherweise gibt es viele ausgereifte und gut unterstützte Technologien, die Webentwicklern dabei helfen, ihre Fähigkeiten in der mobilen Entwicklung anzuwenden. Heute werden wir drei solcher Technologien untersuchen: Cordova, Ionic und React Native. Wir werden React.js, eines der beliebtesten Frameworks für die Front-End-Webentwicklung, als unsere Kernentwicklungstechnologie verwenden. Während wir uns auf die Entwicklung einer iPhone-Anwendung konzentrieren werden, handelt es sich dabei um plattformübergreifende Technologien, die für die Android-Plattform übergreifend kompilierbar sind.

Was wir heute bauen werden

Wir werden eine Anwendung entwickeln, die Natural Language Processing (NLP) verwendet, um Twitter-Feeds zu verarbeiten und zu kuratieren. Die Anwendung ermöglicht es dem Benutzer, eine Reihe von Twitter-Handles auszuwählen, die neuesten Updates mithilfe einer Twitter-API abzurufen und die Tweets nach Stimmung und Thema zu kategorisieren. Der Benutzer kann dann die Tweets basierend auf Stimmung oder Thema anzeigen.

Backend

Bevor wir das Frontend bauen, wollen wir das Backend bauen. Wir werden das Backend vorerst einfach halten – wir werden grundlegende, handelsübliche Stimmungsanalysen und Wortart-Tagging zusammen mit ein wenig Datenbereinigung verwenden, um datensatzspezifische Probleme zu lösen. Wir werden eine Open-Source-NLP-Bibliothek namens TextBlob verwenden und das Ergebnis über Flask bereitstellen.

Sentiment Analysis, Part-of-Speech Tagging und NLP: A Quick Primer

Wenn Sie noch nie mit Anwendungen zur Analyse natürlicher Sprache gearbeitet haben, sind Ihnen diese Begriffe möglicherweise sehr fremd. NLP ist ein Überbegriff für Technologien, die natürliche menschliche Sprachdaten analysieren und verarbeiten. Obwohl dies ein breites Thema ist, gibt es viele Herausforderungen, die allen Technologien gemeinsam sind, die sich mit diesem Bereich befassen. Beispielsweise neigt die menschliche Sprache im Gegensatz zu einer Programmiersprache oder numerischen Daten aufgrund der freizügigen Natur der Grammatik der menschlichen Sprache dazu, lose strukturiert zu sein. Darüber hinaus neigt die menschliche Sprache dazu, extrem kontextabhängig zu sein, und ein Satz, der in einem Kontext geäußert oder geschrieben wird, lässt sich möglicherweise nicht in einen anderen Kontext übersetzen. Abgesehen von Struktur und Kontext ist Sprache äußerst komplex. Wörter weiter unten in einem Absatz können die Bedeutung eines Satzes am Anfang des Absatzes ändern. Vokabeln können erfunden, neu definiert oder geändert werden. All diese Komplexitäten erschweren die übergreifende Anwendung von Datenanalysetechniken.

Sentiment Analysis ist ein Teilgebiet des NLP, das sich darauf konzentriert, die Emotionalität einer natürlichen Sprachpassage zu verstehen. Während menschliche Emotionen von Natur aus subjektiv und daher technisch schwer festzumachen sind, ist die Stimmungsanalyse ein Teilgebiet, das enorme kommerzielle Aussichten hat. Einige Anwendungen der Stimmungsanalyse umfassen die Klassifizierung von Produktbewertungen, um positive und negative Bewertungen verschiedener Merkmale zu identifizieren, die Erkennung der Stimmung einer E-Mail oder einer Rede und die Gruppierung von Liedtexten nach Stimmung. Wenn Sie nach einer eingehenderen Erklärung der Stimmungsanalyse suchen, können Sie hier meinen Artikel zum Erstellen einer auf der Stimmungsanalyse basierenden Anwendung lesen.

Part-of-Speech-Tagging oder POS-Tagging ist ein ganz anderes Teilgebiet. Das Ziel des POS-Tagging ist es, die Wortart eines bestimmten Wortes in einem Satz anhand von grammatikalischen und kontextuellen Informationen zu identifizieren. Diese Beziehung zu erkennen, ist eine viel schwierigere Aufgabe, als es auf den ersten Blick erscheint - ein Wort kann je nach Kontext und Satzbau sehr unterschiedliche Wortarten haben, und die Regeln sind selbst für Menschen nicht immer klar. Glücklicherweise bieten viele handelsübliche Modelle heute leistungsstarke und vielseitige Modelle, die in die meisten wichtigen Programmiersprachen integriert sind. Wenn Sie mehr erfahren möchten, können Sie hier meinen Artikel über POS-Tagging lesen.

Flask, TextBlob und Tweepy

Für unser NLP-Backend verwenden wir Flask, TextBlob und Tweepy. Wir werden Flask verwenden, um einen kleinen, leichtgewichtigen Server zu erstellen, TextBlob, um unsere natürliche Sprachverarbeitung auszuführen, und Tweepy, um Tweets von der Twitter-API abzurufen. Bevor Sie mit dem Codieren beginnen, sollten Sie auch einen Entwicklerschlüssel von Twitter erhalten, damit Sie Tweets abrufen können.

Wir können ein viel ausgefeilteres Backend schreiben und komplexere NLP-Technologien verwenden, aber für unsere heutigen Zwecke werden wir das Backend so einfach wie möglich halten.

Backend-Code

Jetzt können wir mit dem Codieren beginnen. Starten Sie Ihren bevorzugten Python-Editor und Terminal und legen Sie los!

Zuerst wollen wir die erforderlichen Pakete installieren.

 pip install flask flask-cors textblob tweepy python -m textblob.download_corpora

Lassen Sie uns nun den Code für unsere Funktionalität schreiben.

Öffnen Sie ein neues Python-Skript, nennen Sie es server.py und importieren Sie die erforderlichen Bibliotheken:

 import tweepy from textblob import TextBlob from collections import defaultdict

Lassen Sie uns nun einige Hilfsfunktionen schreiben:

 # simple, average a list of numbers with a guard clause to avoid division by zero def mean(lst): return sum(lst)/len(lst) if len(lst) > 0 else 0 # call the textblob sentiment analysis API and noun phrases API and return it as a dict def get_sentiment_and_np(sentence): blob = TextBlob(sentence) return{ 'sentiment': mean([s.sentiment.polarity for s in blob.sentences if s.sentiment.polarity != 0.0]), 'noun_phrases': list(blob.noun_phrases) } # use the tweepy API to get the last 50 posts from a user's timeline # We will want to get the full text if the text is truncated, and we will also remove retweets since they're not tweets by that particular account. def get_tweets(handle): auth = tweepy.OAuthHandler('YOUR_DEVELOPER_KEY') auth.set_access_token('YOUR_DEVELOPER_SECRET_KEY') api = tweepy.API(auth) tl = api.user_timeline(handle, count=50) tweets = [] for tl_item in tl: if 'retweeted_status' in tl_item._json: Continue # this is a retweet if tl_item._json['truncated']: status = api.get_status(tl_item._json['id'], tweet_mode='extended') # get full text tweets.append(status._json['full_text']) else: tweets.append(tl_item._json['text']) return tweets # http and https are sometimes recognized as noun phrases, so we filter it out. # We also try to skip noun phrases with very short words to avoid certain false positives # If this were a commercial app, we would want a more sophisticated filtering strategy. def good_noun_phrase(noun_phrase): noun_phrase_list = noun_phrase.split(' ') for np in noun_phrase_list: if np in {'http', 'https'} or len(np) < 3: return False return True

Nachdem wir nun die Hilfsfunktionen geschrieben haben, können wir alles mit ein paar einfachen Funktionen zusammensetzen:

 # reshapes the tagged tweets into dictionaries that can be easily consumed by the front-end app def group_tweets(processed_tweets): # Sort it by sentiment sentiment_sorted = sorted(processed_tweets, key=lambda x: x['data']['sentiment']) # collect tweets by noun phrases. One tweet can be present in the list of more than one noun phrase, obviously. tweets_by_np = defaultdict(list) for pt in processed_tweets: for np in pt['data']['noun_phrases']: tweets_by_np[np].append(pt) grouped_by_np = {np.title(): tweets for np, tweets in tweets_by_np.items() if len(tweets) > 1 and good_noun_phrase(np)} return sentiment_sorted, grouped_by_np # download, filter, and analyze the tweets def download_analyze_tweets(accounts): processed_tweets = [] for account in accounts: for tweet in get_tweets(account): processed_tweet = ' '.join([i for i in tweet.split(' ') if not i.startswith('@')]) res = get_sentiment_and_np(processed_tweet) processed_tweets.append({ 'account': account, 'tweet': tweet, 'data': res }) sentiment_sorted, grouped_by_np = group_tweets(processed_tweets) return processed_tweets, sentiment_sorted, grouped_by_np

Sie können jetzt die Funktion download_analyze_tweets auf einer Liste von Handles ausführen, denen Sie folgen möchten, und Sie sollten die Ergebnisse sehen.

Ich habe den folgenden Code ausgeführt:

 if __name__ == '__main__': accounts = ['@spacex', '@nasa'] processed_tweets, sentiment_sorted, grouped_by_np = download_analyze_tweets(accounts) print(processed_tweets) print(sentiment_sorted) print(grouped_by_np)

Die Ausführung führte zu den folgenden Ergebnissen. Die Ergebnisse sind natürlich zeitabhängig, wenn Sie also etwas Ähnliches sehen, sind Sie auf dem richtigen Weg.

 [{'account': '@spacex', 'tweet': 'Falcon 9… [{'account': '@nasa', 'tweet': 'Our Mars rove… {'Falcon': [{'account': '@spacex', 'tweet': 'Falc….

Jetzt können wir den Flask-Server aufbauen, was recht einfach ist. Erstellen Sie eine leere Datei namens server.py und schreiben Sie den folgenden Code:

 from flask import Flask, request, jsonify from twitter import download_analyze_tweets from flask_cors import CORS app = Flask(__name__) CORS(app) @app.route('/get_tweets', methods=['POST']) def get_tweets(): accounts = request.json['accounts'] processed_tweets, sentiment_sorted, grouped_by_np = download_analyze_tweets(accounts) return jsonify({ 'processedTweets': processed_tweets, 'sentimentSorted': sentiment_sorted, 'groupedByNp': grouped_by_np }) if __name__ == '__main__': app.run(debug=True)

Führen Sie den Server aus, und Sie sollten jetzt in der Lage sein, mit einem HTTP-Client Ihrer Wahl eine Post-Anforderung an den Server zu senden. Übergeben Sie {accounts: [“@NASA”, “@SpaceX”]} als json-Argument, und Sie sollten sehen, dass die API etwas Ähnliches zurückgibt wie im Twitter-Analysecode.

Jetzt, da wir einen Server haben, können wir das Frontend codieren. Aufgrund einer kleinen Nuance bei der Vernetzung über einen Telefonemulator empfehle ich, dass Sie Ihre API irgendwo bereitstellen. Andernfalls sollten Sie feststellen, ob Ihre App auf einem Emulator ausgeführt wird, und Anforderungen an <Your Computer IP>:5000 statt an localhost:5000 senden, wenn sie sich in einem Emulator befindet. Wenn Sie den Code bereitstellen, können Sie die Anfrage einfach an diese URL senden.

Es gibt viele Möglichkeiten, den Server bereitzustellen. Für einen kostenlosen, einfachen Debug-Server mit minimaler Einrichtung empfehle ich etwas wie PythonAnywhere, das diesen Server sofort ausführen kann.

Nachdem wir nun den Back-End-Server codiert haben, schauen wir uns das Front-End an. Wir beginnen mit einer der bequemsten Optionen für einen Webentwickler: Cordova.

Apache Cordova-Implementierung

Cordova-Primer

Apache Cordova ist eine Softwaretechnologie, die Webentwicklern hilft, mobile Plattformen anzusprechen. Durch Nutzung der auf Smartphone-Plattformen implementierten Webbrowser-Funktionen verpackt Cordova Webanwendungscode in einen nativen Anwendungscontainer, um eine Anwendung zu erstellen. Cordova ist jedoch nicht einfach ein schicker Webbrowser. Über die Cordova-API können Webentwickler auf viele Smartphone-spezifische Funktionen wie Offline-Unterstützung, Ortungsdienste und Gerätekamera zugreifen.

Für unsere Anwendung schreiben wir eine Anwendung mit React.js als JS-Framework und React-Bootstrap als CSS-Framework. Da Bootstrap ein responsives CSS-Framework ist, unterstützt es bereits die Ausführung auf kleineren Bildschirmen. Sobald die Anwendung geschrieben ist, werden wir sie mit Cordova in eine Webanwendung kompilieren.

Konfigurieren der App

Wir beginnen damit, etwas Einzigartiges zu tun, um die Cordova React-App einzurichten. In einem Medium -Artikel erklärt Entwickler Shubham Patil, was wir tun. Im Wesentlichen richten wir eine React-Entwicklungsumgebung mit der React-CLI und dann eine Cordova-Entwicklungsumgebung mit der Cordova-CLI ein, bevor wir die beiden schließlich zusammenführen.

Führen Sie zunächst die folgenden beiden Befehle in Ihrem Codeordner aus:

 cordova create TwitterCurationCordova create-react-app twittercurationreact

Sobald die Einrichtung abgeschlossen ist, möchten wir den Inhalt des öffentlichen und src-Ordners der React-App in die Cordova-App verschieben. Kopieren Sie dann in der Datei „package.json“ die Skripts, die Browserliste und die Abhängigkeiten aus dem React-Projekt. Fügen Sie außerdem "homepage": "./" im Stammverzeichnis von „package.json“ hinzu, um die Kompatibilität mit Cordova zu ermöglichen.

Sobald die Datei „package.json“ zusammengeführt ist, möchten wir die Datei „public/index.html“ so ändern, dass sie mit Cordova funktioniert. Öffnen Sie die Datei und kopieren Sie die Meta-Tags von www/index.html sowie das Skript am Ende des Body-Tags, wenn Cordova.js geladen wird.

Ändern Sie als Nächstes die Datei src/index.js, um festzustellen, ob sie auf Cordova ausgeführt wird. Wenn es auf Cordova ausgeführt wird, möchten wir den Rendercode innerhalb des Deviceready-Ereignishandlers ausführen. Wenn es in einem normalen Browser ausgeführt wird, rendern Sie einfach sofort.

 const renderReactDom = () => { ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); } if (window.cordova) { document.addEventListener('deviceready', () => { renderReactDom(); }, false); } else { renderReactDom(); }

Schließlich müssen wir unsere Bereitstellungspipeline einrichten. Fügen Sie die folgende Definition in die Datei config.xml ein:

<hook type="before_prepare" src="hooks/prebuild.js" />

Und fügen Sie das folgende Skript in prebuild.js ein:

 const path = require('path'); const { exec } = require('child_process'); const fs = require('fs'); const rimraf = require('rimraf'); function renameOutputFolder(buildFolderPath, outputFolderPath) { return new Promise((resolve, reject) => { fs.rename(buildFolderPath, outputFolderPath, (err) => { if (err) { reject(err); } else { resolve('Successfully built!'); } }); }); } function execPostReactBuild(buildFolderPath, outputFolderPath) { return new Promise((resolve, reject) => { if (fs.existsSync(buildFolderPath)) { if (fs.existsSync(outputFolderPath)) { rimraf(outputFolderPath, (err) => { if (err) { reject(err); return; } renameOutputFolder(buildFolderPath, outputFolderPath) .then(val => resolve(val)) .catch(e => reject(e)); }); } else { renameOutputFolder(buildFolderPath, outputFolderPath) .then(val => resolve(val)) .catch(e => reject(e)); } } else { reject(new Error('build folder does not exist')); } }); } module.exports = () => { const projectPath = path.resolve(process.cwd(), './node_modules/.bin/react-scripts'); return new Promise((resolve, reject) => { exec(`${projectPath} build`, (error) => { if (error) { console.error(error); reject(error); return; } execPostReactBuild(path.resolve(__dirname, '../build/'), path.join(__dirname, '../www/')) .then((s) => { console.log(s); resolve(s); }) .catch((e) => { console.error(e); reject(e); }); }); }); };

Dadurch wird der React-Build ausgeführt und der Build-Ordner an der entsprechenden Stelle abgelegt, bevor der Cordova-Build gestartet wird, wodurch der Bereitstellungsprozess automatisiert wird.

Jetzt können wir versuchen, unsere App auszuführen. Führen Sie Folgendes in der Befehlszeile aus:

 npm install rimraf npm install npm run start

Sie sollten sehen, dass die React-App im Browser eingerichtet ist und ausgeführt wird. Jetzt Cordova hinzufügen:

 cordova platform add iOS cordova run iOS

Und Sie sollten sehen, dass die React-App im Emulator läuft.

Router- und Paket-Setup

Um einen Teil der Infrastruktur einzurichten, die wir zum Erstellen der App benötigen, beginnen wir mit der Installation der erforderlichen Pakete:

 npm install react-bootstrap react-router react-router-dom

Wir werden jetzt das Routing einrichten und dabei auch ein einfaches globales Zustandsobjekt einrichten, das von allen Komponenten gemeinsam genutzt wird. In einer Produktionsanwendung möchten wir ein Zustandsverwaltungssystem wie Redux oder MobX verwenden, aber wir werden es vorerst einfach halten. Gehen Sie zu App.js und konfigurieren Sie die Route folgendermaßen:

 import { BrowserRouter as Router, Redirect, Route, } from "react-router-dom"; function App() { const [curatedTweets, setCuratedTweets] = useState(); return <Router> <Route path="/" exact render={() => <Input setCuratedTweets={setCuratedTweets} />} /> <Route path="/display" render={() => <Display curatedTweets={curatedTweets} />} /> <Route path="*" exact render={() => <Redirect to="/" />} /> </Router> }

Mit dieser Routendefinition haben wir zwei Routen eingeführt, die wir implementieren müssen: Eingabe und Anzeige. Beachten Sie, dass die Variable curatedTweets an Display und die Variable setCuratedTweets an Input übergeben wird. Das bedeutet, dass die Eingabekomponente die Funktion aufrufen kann, um die curatedTweets Variable festzulegen, und Display erhält die anzuzeigende Variable.

Um mit dem Codieren der Komponenten zu beginnen, erstellen wir einen Ordner unter /src mit dem Namen /src/components. Erstellen Sie unter /src/components einen weiteren Ordner namens /src/components/input und darunter zwei Dateien: input.js und input.css. Machen Sie dasselbe für die Display-Komponente – erstellen Sie /src/components/display und darunter: display.js und display.css.

Unter diesen erstellen wir Stub-Komponenten wie folgt:

 import React from 'react'; import 'input.css' const Input = () => <div>Input</div>; export default Input

Und das gleiche für Anzeige:

 import React from 'react'; import display.css' const Display = () => <div>Display</div>; export default Display

Damit ist unser Wireframing abgeschlossen und die App sollte laufen. Lassen Sie uns nun die Eingabeseite codieren.

Eingabeseite

Big-Picture-Plan

Bevor wir den Code schreiben, überlegen wir uns, was unsere Input-Seite machen soll. Natürlich möchten wir, dass die Benutzer die Twitter-Handles eingeben und bearbeiten können, von denen sie ziehen möchten. Wir möchten auch, dass die Benutzer angeben können, dass sie fertig sind. Wenn die Benutzer angeben, dass sie fertig sind, möchten wir die kuratierten Tweets aus unserer Python-Kurations-API ziehen und schließlich zur Display-Komponente navigieren.

Jetzt, da wir wissen, was unsere Komponente tun soll, können wir codieren.

Einrichten der Datei

Beginnen wir damit, die React Router-Bibliothek mit withRouter zu importieren, um Zugriff auf die Navigationsfunktionen zu erhalten, die React Bootstrap-Komponenten, die wir benötigen, wie folgt:

 import React, {useState} from 'react'; import {withRouter} from 'react-router-dom'; import {ListGroup, Button, Form, Container, Row, Col} from 'react-bootstrap'; import './input.css';

Lassen Sie uns nun die Stub-Funktion für Input definieren. Wir wissen, dass Input die setCuratedTweets Funktion erhält, und wir möchten ihr auch die Möglichkeit geben, zur Anzeigeroute zu navigieren, nachdem sie die kuratierten Tweets von unserer Python-API festgelegt hat. Daher wollen wir aus dem Requisiten setCuratedTweets und History (für die Navigation) nehmen.

 const Input = ({setCuratedTweets, history}) => { return <div>Input</div> }

Um ihm den Verlaufs-API-Zugriff zu geben, werden wir ihn mit withRouter in der export-Anweisung am Ende der Datei umschließen:

 export default withRouter(Input);

Datencontainer

Lassen Sie uns die Datencontainer mit React Hooks einrichten. Wir haben den useState Hook bereits importiert, damit wir den folgenden Code zum Hauptteil der Input-Komponente hinzufügen können:

 const [handles, setHandles] = useState([]); const [handleText, setHandleText] = useState('');

Dadurch werden der Container und Modifikatoren für Handles erstellt, die die Liste der Handles enthalten, aus denen der Benutzer ziehen möchte, und handleText , der den Inhalt des Textfelds enthält, das der Benutzer zur Eingabe des Handles verwendet.

Lassen Sie uns nun die UI-Komponenten programmieren.

UI-Komponenten

Die UI-Komponenten werden ziemlich einfach sein. Wir haben eine Bootstrap-Zeile, die das Eingabetextfeld zusammen mit zwei Schaltflächen enthält, eine zum Hinzufügen des aktuellen Eingabefeldinhalts zur Liste der Handles und eine zum Abrufen aus der API. Wir haben eine weitere Bootstrap-Zeile, die die Liste der Handles anzeigt, die der Benutzer mithilfe der Bootstrap-Listengruppe abrufen möchte. Im Code sieht das so aus:

 return ( <Container className="tl-container"> <Row> <Col> <Form.Control type="text" value={handleText} onChange={changeHandler} placeholder="Enter handle to pull" /> </Col> </Row> <Row className='input-row'> <Col> <Button variant="primary" onClick={getPull}>Pull</Button> {' '} <Button variant="success" onClick={onAddClicked}>Add</Button> </Col> </Row> <Row> <Col> <ListGroup className="handles-lg"> {handles.map((x, i) => <ListGroup.Item key={i}> {x} <span onClick={groupItemClickedBuilder(i)} className="delete-btn-span"> <Button variant="danger" size="sm"> delete </Button> </span> </ListGroup.Item>)} </ListGroup> </Col> </Row> </Container> );

Zusätzlich zur UI-Komponente wollen wir die drei UI-Event-Handler implementieren, die Datenänderungen handhaben. Der getPull Ereignishandler, der die API aufruft, wird im nächsten Abschnitt implementiert.

 // set the handleText to current event value const textChangeHandler = (e) => { e.preventDefault(); setHandleText(e.target.value); } // Add handleText to handles, and then empty the handleText const onAddClicked = (e) => { e.preventDefault(); const newHandles = [...handles, handleText]; setHandles(newHandles); setHandleText(''); } // Remove the clicked handle from the list const groupItemClickedBuilder = (idx) => (e) => { e.preventDefault(); const newHandles = [...handles]; newHandles.splice(idx, 1); setHandles(newHandles); }

Jetzt sind wir bereit, den API-Aufruf zu implementieren.

API-Aufruf

Für den API-Aufruf möchten wir die Handles, die wir abrufen möchten, in einer POST-Anforderung an die Python-API senden und das resultierende JSON-Ergebnis in die Variable curatedTweets . Wenn alles gut geht, wollen wir dann programmgesteuert zur /display-Route navigieren. Andernfalls protokollieren wir den Fehler in der Konsole, damit wir ihn einfacher debuggen können.

Im Codemodus sieht das so aus:

 const pullAPI = (e) => { e.preventDefault(); fetch('http://prismatic.pythonanywhere.com/get_tweets', { method: 'POST', mode: 'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ accounts: handles }) }).then(r=>r.json()).then(j => { setCuratedTweets(j); history.push('/display'); }) .catch(e => { console.log(e); }) }

Und damit sollten wir startklar sein. Fühlen Sie sich frei, die App auszuführen, ein paar Handles hinzuzufügen und eine Anfrage an die API zu senden.

Jetzt können wir die Stimmungsseite codieren.

Stimmungssortierter Modus

Da die Python-API die Tweets bereits nach Stimmung sortiert, ist die Stimmungsseite eigentlich nicht allzu schwierig, sobald wir das Ergebnis von der Python-API haben.

Big-Picture-Plan

Wir wollen eine Listenschnittstelle, um die Tweets anzuzeigen. Wir möchten auch, dass einige Navigationskomponenten in den Themengruppierungsmodus wechseln und zur Eingabeseite zurückkehren.

Zunächst definieren wir die Unterkomponente des SentimentDisplay-Modus in der Datei display.js.

SentimentDisplay-Komponente

Das SentimentDisplay nimmt das Objekt curatedTweets und zeigt die nach Sentiment sortierten Tweets in einer Liste an. Mit Hilfe von React-Bootstrap ist die Komponente recht einfach:

 const SentimentDisplay = ({curatedTweets}) => { return <ListGroup> {curatedTweets.sentimentSorted.map((x, i) => <ListGroup.Item key={i}> <div className="account-div">{x.account}:</div> <span className="tweet-span">{x.tweet}</span> <span className="sentiments-span">({x.data.sentiment.toPrecision(2)})</span> </ListGroup.Item> )} </ListGroup> }

Wenn wir schon dabei sind, lassen Sie uns auch etwas Styling hinzufügen. Fügen Sie Folgendes in display.css ein und importieren Sie es:

 .account-div { font-size: 12px; font-weight: 600; } .tweet-span { font-size: 11px; font-weight: 500; } .sentiments-span { font-size: 10px; } .tl-container { margin-top: 10px; } .disp-row { margin-top: 5px; }

Wir können jetzt die SentimentDisplay-Komponente anzeigen. Ändern Sie die Display wie folgt:

 const Display = ({curatedTweets}) => { return <SentimentDisplay curatedTweets={curatedTweets} /> };

Lassen Sie uns diese Gelegenheit auch nutzen, um die Navigationskomponenten zu codieren. Wir brauchen zwei Schaltflächen – die Schaltfläche „Zurück zur Bearbeitung“ und den Themengruppenmodus.

Wir können diese Schaltflächen wie folgt in einer separaten Bootstrap-Zeile direkt über der SentimentDisplay-Komponente implementieren:

 Return <Container className="tl-container"> <Row> <Col> <Link to="/"><Button variant='primary'>Back</Button></Link> {' '} <Button variant='success'>View by Topic</Button> </Col> </Row> <Row className="disp-row"> <Col> <SentimentDisplay curatedTweets={curatedTweets} /> </Col> </Row> </Container>

Führen Sie die App aus und ziehen Sie die Tweets von ein paar Griffen. Sieht ziemlich schick aus!

Themengruppierungsmodus

Nun wollen wir den Topic Grouping Mode implementieren. Es ist etwas komplexer als das SentimentDisplay, aber auch hier helfen uns einige sehr praktische Bootstrap-Komponenten enorm.

Big-Picture-Plan

Wir erhalten alle Nominalphrasen und zeigen sie als Akkordeonliste an. Wir werden dann die Tweets rendern, die die Nominalphrasen enthalten, sobald die Akkordeonliste erweitert ist.

Implementieren des Umschaltens in den Themengruppierungsmodus

Lassen Sie uns zunächst Logik implementieren, um vom Stimmungsmodus in den Themengruppierungsmodus zu wechseln. Beginnen wir damit, zuerst die Stub-Komponente zu erstellen:

 const TopicDisplay = () => { return <div>Topic Display</div> }

Und legen Sie eine Logik fest, um einen Modus zum Anzeigen zu erstellen. Fügen Sie in der Hauptanzeigekomponente die folgenden Zeilen hinzu, um die Logik zu erstellen, für die die Komponente angezeigt wird.

 // controls the display mode. Remember to import {useState} from 'react' const [displayType, setDisplayType] = useState('Sentiment'); // Switch the Display Mode const toggleDisplayType = () => { setDisplayType(displayType === 'Sentiment' ? 'Topic': 'Sentiment'); } // determines the text on the mode switch button const switchStr = displayType === 'Sentiment'? 'View by Topic': 'View by Sentiment'

Und ändern Sie den JSX wie folgt, um die Logik hinzuzufügen:

 Return <Container className="tl-container"> <Row> <Col> <Link to="/"><Button variant='primary'>Back</Button></Link> {' '} <Button variant='success' onClick={toggleDisplayType}>{switchStr}</Button> </Col> </Row> <Row className="disp-row"> <Col> { displayType === 'Sentiment'? <SentimentDisplay curatedTweets={curatedTweets} />: <TopicDisplay curatedTweets={curatedTweets} /> } </Col> </Row> </Container>

Jetzt sollten Sie beim Umschalten den Stub der Themengruppenanzeige sehen.

Die TopicDisplay-Komponente

Jetzt können wir die TopicDisplay Komponente codieren. Wie bereits erwähnt, wird die Bootstrap-Akkordeonliste genutzt. Die Umsetzung ist eigentlich recht einfach:

 const TopicDisplay = ({curatedTweets}) => { return <Accordion> {Object.keys(curatedTweets.groupedByNp).map((x, i) => <Card key={i}> <Card.Header> <Accordion.Toggle as={Button} variant="link" eventKey={i}> {x} ({curatedTweets.groupedByNp[x].length}) </Accordion.Toggle> </Card.Header> <Accordion.Collapse eventKey={i}> <Card.Body> <ListGroup> {curatedTweets.groupedByNp[x].map((y, i2) => <ListGroup.Item key={i2}> <div className="account-div">{y.account}:</div> <span className="tweet-span">{y.tweet}</span> <span className="sentiments-span">({y.data.sentiment.toPrecision(2)})</span> </ListGroup.Item> )} </ListGroup> </Card.Body> </Accordion.Collapse> </Card> )} </Accordion> }

Führen Sie die App aus, und Sie sollten die Themenanzeige sehen.

Jetzt ist die App fertig und wir sind bereit, die App für den Emulator zu erstellen.

Ausführen der App im Emulator

Cordova macht es sehr einfach, die App im Emulator auszuführen. Einfach ausführen:

 cordova platform add ios # if you haven't done so already cordova run ios

Und Sie sollten die App im Emulator sehen. Da es sich bei Bootstrap um eine responsive Web-App handelt, passt sich die Web-App an die Breite eines iPhones an und alles sieht ganz nett aus.

Wenn die Cordova-App fertig ist, schauen wir uns nun die Ionic-Implementierung an.

Ionic-React-Implementierung

Ionischer Primer

Ionic ist eine Webkomponentenbibliothek und ein CLI-Toolkit, das das Erstellen von Hybridanwendungen vereinfacht. Ursprünglich wurde Ionic auf AngularJS und Cordova aufgebaut, aber seitdem haben sie ihre Komponenten in React.js veröffentlicht und begonnen, Capacitor zu unterstützen, eine Plattform ähnlich wie Cordova. Was Ionic auszeichnet, ist, dass sich die Komponenten, obwohl Sie Webkomponenten verwenden, einer nativen mobilen Benutzeroberfläche sehr ähnlich fühlen. Darüber hinaus passt sich das Erscheinungsbild der Ionic-Komponenten automatisch an das Betriebssystem an, auf dem sie ausgeführt wird, was wiederum dazu beiträgt, dass die Anwendung nativer und natürlicher aussieht und sich anfühlt. Schließlich, obwohl dies außerhalb des Rahmens unseres Artikels liegt, bietet Ionic auch mehrere Build-Tools, die die Bereitstellung Ihrer Anwendung ein wenig einfacher machen.

Für unsere Anwendung werden wir die React-Komponenten von Ionic verwenden, um die Benutzeroberfläche zu erstellen, während wir einen Teil der JavaScript-Logik nutzen, die wir im Cordova-Abschnitt erstellt haben.

Konfigurieren der App

Zuerst wollen wir die Ionic-Tools installieren. Lassen Sie uns also Folgendes ausführen:

 npm install -g @Ionic/cli native-run cordova-res

Und nachdem die Installation abgeschlossen ist, gehen wir zum Projektordner. Jetzt verwenden wir die Ionic CLI, um unseren neuen Projektordner zu erstellen:

 ionic start twitter-curation-Ionic blank --type=react --capacitor

Beobachten Sie, wie die Magie geschieht, und gehen Sie jetzt in den Ordner mit:

 cd twitter-curation-Ionic

Und führen Sie die leere App aus mit:

 ionic serve

Damit ist unsere App eingerichtet und einsatzbereit. Lassen Sie uns einige Routen definieren.

Bevor wir fortfahren, werden Sie feststellen, dass Ionic das Projekt mit TypeScript gestartet hat. Ich gebe mir zwar keine Mühe, TypeScript zu verwenden, aber es hat einige sehr nette Funktionen, und wir werden es für diese Implementierung verwenden.

Router-Setup

Für diese Implementierung verwenden wir drei Routen: input, sentimentDisplay und topicDisplay . Wir tun dies, weil wir die von Ionic bereitgestellten Übergangs- und Navigationsfunktionen nutzen möchten und weil wir Ionic-Komponenten verwenden und Akkordeonlisten nicht mit Ionic vorinstalliert sind. Wir können natürlich unsere eigenen implementieren, aber für dieses Tutorial bleiben wir bei den bereitgestellten Ionic-Komponenten.

Wenn Sie zu App.tsx navigieren, sollten Sie die bereits definierten grundlegenden Routen sehen.

Eingabeseite

Big-Picture-Plan

Wir verwenden viel ähnliche Logik und ähnlichen Code wie die Bootstrap-Implementierung, mit einigen wesentlichen Unterschieden. Zuerst werden wir TypeScript verwenden, was bedeutet, dass wir Typannotationen für unseren Code haben werden, die Sie im nächsten Abschnitt sehen werden. Zweitens werden wir Ionic-Komponenten verwenden, die im Stil Bootstrap sehr ähnlich sind, aber in ihrem Design OS-empfindlich sein werden. Schließlich werden wir wie in der Bootstrap-Version dynamisch mit der Verlaufs-API navigieren, aber aufgrund der Ionic Router-Implementierung etwas anders auf den Verlauf zugreifen.

Einrichten

Beginnen wir damit, die Eingabekomponente mit einer Stub-Komponente einzurichten. Erstellen Sie einen Ordner unter den Seiten mit dem Namen input und erstellen Sie darunter eine Datei mit dem Namen Input.tsx. Fügen Sie in dieser Datei den folgenden Code ein, um eine React-Komponente zu erstellen. Beachten Sie, dass es etwas anders ist, weil wir TypeScript verwenden.

 import React, {useState} from 'react'; const Input : React.FC = () => { return <div>Input</div>; } export default Input;

Und ändern Sie die Komponente in App.tsx in:

 const App: React.FC = () => ( <IonApp> <IonReactRouter> <IonRouterOutlet> <Route path="/input" component={Input} exact={true} /> <Route exact path="/" render={() => <Redirect to="/input" />} /> </IonRouterOutlet> </IonReactRouter> </IonApp> );

Wenn Sie jetzt die App aktualisieren, sollten Sie die Input-Stub-Komponente sehen.

Datencontainer

Lassen Sie uns jetzt die Datencontainer erstellen. Wir wollen die Container für eingegebene Twitter-Handles sowie den aktuellen Inhalt des Eingabefelds. Da wir TypeScript verwenden, müssen wir die Typanmerkungen zu unserem useState Aufruf in der Komponentenfunktion hinzufügen:

 const Input : React.FC = () => { const [text, setText] = useState<string>(''); const [accounts, setAccounts] = useState<Array<string>>([]); return <div>Input</div>; }

Wir möchten auch, dass ein Datencontainer die Rückgabewerte der API enthält. Da der Inhalt davon mit den anderen Routen geteilt werden muss, definieren wir sie auf der App.tsx-Ebene. Importieren useState von React in die App.tsx-Datei und ändern Sie die App-Container-Funktion wie folgt:

 const App: React.FC = () => { const [curatedTweets, setCuratedTweets] = useState<CuratedTweets>({} as CuratedTweets); return ( <IonApp> <IonReactRouter> <IonRouterOutlet> <Route path="/input" component={Input} exact={true} /> <Route exact path="/" render={() => <Redirect to="/input" />} /> </IonRouterOutlet> </IonReactRouter> </IonApp> ); }

Wenn Sie an dieser Stelle einen Editor mit Syntaxhervorhebung wie Visual Studio Code verwenden, sollten die CuratedTweets aufleuchten. Dies liegt daran, dass die Datei nicht weiß, wie die Oberfläche von CuratedTweets aussieht. Lassen Sie uns das jetzt definieren. Erstellen Sie unter src einen Ordner mit dem Namen Interfaces und erstellen Sie darin eine Datei namens CuratedTweets.tsx. Definieren Sie in der Datei die CuratedTweets-Schnittstelle wie folgt:

 interface TweetRecordData { noun_phrases: Array<string>, sentiment: number } export interface TweetRecord { account: string, data: TweetRecordData, tweet: string } export default interface CuratedTweets { groupedByNp: Record<string, Array<TweetRecord>>, processedTweets: Array<TweetRecord>, sentimentSorted: Array<TweetRecord> }

Jetzt kennt die App die Struktur der API-Rückgabedaten. Importieren Sie die CuratedTweets-Schnittstelle in App.tsx. Sie sollten die App.tsx jetzt problemlos kompilieren sehen.

Wir müssen hier noch ein paar Dinge tun. Wir müssen die setCuratedTweets Funktion an die Input-Komponente übergeben und die Input-Komponente auf diese Funktion aufmerksam machen.

Ändern Sie in der App.tsx die Eingaberoute wie folgt:

 <Route path="/input" render={() => <Input setCuratedTweets={setCuratedTweets}/>} exact={true} />

Jetzt sollten Sie sehen, dass der Editor etwas anderes anzeigt - Input weiß nicht, dass die neue Requisite an ihn übergeben wird, also sollten wir ihn in Input.tsx definieren.

First, import the CuratedTweets interface, then define the ContainerProps interface like so:

 interface ContainerProps { setCuratedTweets: React.Dispatch<React.SetStateAction<CuratedTweets>> }

And finally, change the Input component definition like so:

 const Input : React.FC<ContainerProps> = ({setCuratedTweets}) => { const [text, setText] = useState<string>(''); const [accounts, setAccounts] = useState<Array<string>>([]); return <div>Input</div>; }

We are done defining the data containers, and now, onto building the UI components.

UI Components

For the UI component, we will want to build an input component and a list display component. Ionic provides some simple containers for these.

Let's start by importing the library components we'll be using:

 import { IonInput, IonItem, IonList, IonButton, IonGrid, IonRow, IonCol } from '@Ionic/react';

Now, we can replace the stub component with the IonInput , wrapped in an IonGrid:

 return <IonGrid> <IonRow> <IonCol> <IonInput value={text} placeholder="Enter accounts to pull from" onIonChange={e => setText(e.detail.value!)} /> </IonCol> </IonRow> </IonGrid>

Notice that the event listener is onIonChange instead of onChange . Otherwise, it should look very familiar.

When you open the app in your browser, it may not look like the Bootstrap app. However, if you set your browser to emulator mode, the UI will make more sense. It will look even better once you deploy it on mobile, so look forward to it.

Now, let's add some buttons. We will want an “Add to list” button and a “Pull API” button. For that, we can use IonButton. Change the size of the input's IonCol to 8 and add the following two buttons with columns:

 <IonCol size="8"> <IonInput value={text} placeholder="Enter accounts to pull from" onIonChange={e => setText(e.detail.value!)} /> </IonCol> <IonCol size="2"> <IonButton style={{float: 'right'}} color="primary" size="small" onClick={onAddClicked}>Add</IonButton> </IonCol> <IonCol size="2"> <IonButton style={{float: 'right'}} color="success" size="small" onClick={onPullClicked}>Pull</IonButton> </IonCol>

Since we're writing the buttons, let's write the event handlers as well.

The handler to add a Twitter handle to the list is simple:

 const onAddClicked = () => { if (text === undefined || text.length === 0) { return; } const newAccounts: Array<string> = [...accounts, text]; setAccounts(newAccounts); setText(''); }

We will implement the API call in the next section, so let's just put a stub function for onPullClicked :

 const onPullClicked = () => {}

Now, we need to write the component for displaying the list of handles that has been inputted by the user. For that, we will use IonList, put into a new IonRow:

 <IonRow> <IonCol> <IonList> {accounts.map((x:string, i:number) => <IonItem key={i}> <IonGrid> <IonRow> <IonCol size="8" style={{paddingTop: '12px'}}>{x}</IonCol> <IonCol><IonButton style={{float: 'right'}} color="danger" size="small" onClick={deleteClickedBuilder(i)}>Delete</IonButton></IonCol> </IonRow> </IonGrid> </IonItem>)} </IonList> </IonCol> </IonRow>

Each list item is displaying the handle and a delete button in its very own IonGrid. For this code to compile, we will want to implement the deleteClickedHandler as well. It should be very familiar from the previous section but with TypeScript annotations.

 const deleteClickedBuilder = (idx: number) => () => { const newAccounts: Array<string> = [...accounts]; newAccounts.splice(idx, 1); setAccounts(newAccounts); }

Save this, and you should see the Input page with all the UI components implemented. We can add handles, delete handles, and click the button to invoke the API.

As a final exercise, let's move the in-line styles to CSS. Create a file in the input folder called input.css and import it in the Input.tsx file. Then, add the following styles:

 .input-button { float: right; } .handle-display { padding-top: 12px; }

Now, add className="input-button” on all of the IonButtons and className=”handle-display” on the handle list item IonCol that is displaying the intended Twitter handle. Save the file, and you should see everything looking quite good.

API Call

The code to pull the API is very familiar from the previous section, with one exception - we have to get access to the history component to be able to dynamically change routes. We will do this using the withHistory hook.

We first import the hook:

 import { useHistory } from 'react-router';

And then implement the handler in the input component:

 const history = useHistory(); const switchToDisplay = () => { history.push('/display'); } const onPullClicked = () => { fetch('http://prismatic.pythonanywhere.com/get_tweets', { method: 'POST', mode: 'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ accounts }) }).then(r=>r.json()).then(j => { setCuratedTweets(j); switchToDisplay(); }) .catch(e => { console.log(e); }) }

Kopfzeile hinzufügen

Our Input page looks quite nice, but it looks a little bare due to Ionic's mobile-centric styling. To make the UI look more natural, Ionic provides a header feature that lets us provide a more natural user experience. When running on mobile, the header will also simulate the native OS's mobile platform, which makes the user experience even more natural.

Change your component import to:

 import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonInput, IonItem, IonList, IonButton, IonGrid, IonRow, IonCol } from '@Ionic/react';

And now wrap the UI in an Ionic page with a header, like so:

return <IonPage> <IonHeader> <IonToolbar> <IonTitle>Twitter Curation App</IonTitle> </IonToolbar> </IonHeader> <IonContent> <IonHeader collapse="condense"> <IonToolbar> <IonTitle size="large">Twitter Curation App</IonTitle> </IonToolbar> </IonHeader> <IonGrid> <IonRow> <IonCol size="8"> <IonInput value={text} placeholder="Enter accounts to pull from" onIonChange={e => setText(e.detail.value!)} /> </IonCol> <IonCol size="2"> <IonButton className="input-button" color="primary" size="small" onClick={onAddClicked}>Add</IonButton> </IonCol> <IonCol size="2"> <IonButton className="input-button" color="success" size="small" onClick={onPullClicked}>Pull</IonButton> </IonCol> </IonRow> <IonRow> <IonCol> <IonList> {accounts.map((x:string, i:number) => <IonItem key={i}> <IonGrid> <IonRow> <IonCol size="8" className="handle-display">{x}</IonCol> <IonCol><IonButton className="input-button" color="danger" size="small" onClick={deleteClickedBuilder(i)}>Delete</IonButton></IonCol> </IonRow> </IonGrid> </IonItem>)} </IonList> </IonCol> </IonRow> </IonGrid> </IonContent> </IonPage>

Das sieht jetzt schön aus!

Sentimentsortierte Seite

Big-Picture-Plan

Die nach Sentiment sortierte Seite ähnelt weitgehend der nach Sentiment sortierten Seite der Bootstrap-Seite, verwendet jedoch TypeScript und Ionic. Wir werden die Themenanzeige auch als separate Route implementieren, um die Navigationsfunktionen von Ionic auf Mobilgeräten nutzen zu können. Daher müssen wir dieser Seite die Möglichkeit geben, auch zur Themenanzeige-Route zu navigieren.

Routen-Setup

Beginnen wir damit, einen neuen Ordner namens sentimentsorted und darunter eine Datei namens SentimentSorted.tsx zu erstellen. Exportieren Sie eine Stub-Komponente wie folgt:

 import React from 'react'; const SentimentSorted: React.FC = () => { return <div>Sentiment Sorted</div> } export default SentimentSorted;

Importieren Sie in App.tsx die Komponente:

 import SentimentSorted from './pages/sentimentsorted/SentimentSorted';

Und fügen Sie die Route hinzu:

 <Route path="/display" render={() => <SentimentSorted curatedTweets={curatedTweets} />} />

Sie erhalten einen TypeScript-Fehler, der besagt, dass SentimentSorted die curatedTweets-Requisiten nicht erwartet, also kümmern wir uns jetzt im nächsten Abschnitt darum.

UI-Komponenten

Beginnen wir mit der Definition der Props des Containers. Ähnlich wie die Eingabekomponente:

 import CuratedTweets from '../../interfaces/CuratedTweets'; interface ContainerProps { curatedTweets: CuratedTweets }

Und jetzt ändern Sie die Stub-Anzeige:

 const SentimentSorted: React.FC<ContainerProps> = ({curatedTweets}) => { return <div>Sentiment Sorted</div> }

Und alles sollte kompilieren.

Die Anzeige ist sehr einfach, es ist nur eine IonList mit Anzeigekomponenten:

 return <IonGrid> <IonRow> <IonCol> <IonList> {(curatedTweets.sentimentSorted).map((x, i) => <IonItem key={i}> <IonLabel className="ion-text-wrap"> <h2>{x.account}:</h2> <h3>{x.tweet}</h3> <p>({x.data.sentiment.toPrecision(2)})</p> </IonLabel> </IonItem>)} </IonList> </IonCol> </IonRow> </IonGrid>

Wenn Sie einige Tweets mit der Eingabekomponente speichern und abrufen, sollten Sie die Tweets in einer Liste angezeigt sehen.

Lassen Sie uns nun die Navigationsschaltflächen hinzufügen. Zum IonGrid hinzufügen:

 <IonRow> <IonCol> <IonButton color='primary' onClick={switchToInput}>Back</IonButton> <IonButton color="success" onClick={toggleDisplayType}>{switchStr}</IonButton> </IonCol> </IonRow>

Der switchToInput ist sehr einfach mit der History-API zu implementieren:

 const switchToInput = () => { history.goBack(); }

Und ToggleDisplayType sollte auch bekannt sein:

 const toggleDisplayType = () => { setDisplayType(displayType === 'Sentiment' ? 'Topic': 'Sentiment'); } const switchStr = displayType === 'Sentiment'? 'View by Topic': 'View by Sentiment'

Jetzt haben wir die SentimentDisplay Komponente implementiert. Bevor wir nun die Themenanzeigeseite implementieren, müssen wir die Komponente implementieren, die alle Themen anzeigt. Das werden wir im nächsten Abschnitt tun.

Themengruppen-Komponente

Lassen Sie uns eine Anzeigeoption für die Themenliste hinzufügen und sie bedingt anzeigen. Dazu müssen wir die Sentiment Display-Liste aufschlüsseln. Benennen Sie SentimentDisplay in Display um und lassen Sie uns die Stimmungsanzeigeliste aufschlüsseln:

 interface SentimentDisplayProps { sentimentSorted: Array<TweetRecord> } const SentimentDisplay: React.FC<SentimentDisplayProps> = ({sentimentSorted}) => { return <IonList> {(sentimentSorted || []).map((x, i) => <IonItem key={i}> <IonLabel className="ion-text-wrap"> <h2>{x.account}:</h2> <h3>{x.tweet}</h3> <p>({x.data.sentiment.toPrecision(2)})</p> </IonLabel> </IonItem>)} </IonList> }

Beachten Sie, wie wir eine der Klassendefinitionen in der CuratedTweets-Schnittstelle verwenden. Das liegt daran, dass diese Komponenten nicht das gesamte CuratedTweets-Objekt benötigen, sondern nur eine Teilmenge. Die Themenliste ist sehr ähnlich:

 interface TopicDisplayProps { groupedByNP: Record<string, Array<TweetRecord>> } const TopicDisplay: React.FC<TopicDisplayProps> = ({groupedByNP}) => { return <IonList> {Object.keys(groupedByNP || {}).map((x, i) => <IonItem key={i} routerLink={`/topicDisplay/${encodeURIComponent(x)}`}> <IonLabel className="ion-text-wrap"> <h2>{x} ({groupedByNP[x].length})</h2> </IonLabel> </IonItem>)} </IonList> }

Und jetzt ist die bedingte Anzeige einfach in der Anzeigekomponente einzurichten:

 return ( <IonGrid> <IonRow> <IonCol> <IonButton color='primary' onClick={switchToInput}>Back</IonButton> <IonButton color="success" onClick={toggleDisplayType}>{switchStr}</IonButton> </IonCol> </IonRow> { displayType === 'Sentiment'? <SentimentDisplay sentimentSorted={curatedTweets.sentimentSorted} /> : <TopicDisplay groupedByNP={curatedTweets.groupedByNp} /> } </IonGrid> );

Stellen Sie sicher, dass Sie den Standardexport ändern, und jetzt können wir die Themenanzeigeseite implementieren.

Themenanzeigeseite

Big-Picture-Plan

Die Themenanzeigeseite ist eine Listenanzeige ähnlich der Stimmungsanzeige, aber wir suchen nach dem betreffenden Thema aus dem Routenparameter.

Routen-Setup

Wenn Sie so weit gekommen sind, sollten Sie bereits wissen, was zu tun ist. Lassen Sie uns einen Seitenordner namens topicdisplay und eine TopicDisplay.tsx erstellen, eine Stub-Komponente schreiben und sie in die App.tsx-Seite importieren. Lassen Sie uns nun die Routen einrichten:

 <Route path="/topicDisplay/:topic" render={() => <TopicDisplay curatedTweets={curatedTweets} /> } />

Jetzt sind wir bereit, die UI-Komponente zu implementieren.

UI-Komponenten

Lassen Sie uns zunächst die ContainerProps -Definition erstellen:

 interface ContainerProps { curatedTweets: CuratedTweets } const TopicDisplay: React.FC<ContainerProps> = ({curatedTweets}) => { Return <div>Topic Display</div> }

Jetzt müssen wir das Thema aus dem URL-Pfadnamen abrufen. Dazu verwenden wir die Verlaufs-API. Importieren wir also useHistory , instanziieren die Verlaufs-API und ziehen das Thema aus dem Pfadnamen. Wenn wir schon dabei sind, implementieren wir auch die Switch-Back-Funktion:

 const TopicDisplay: React.FC<ContainerProps> = ({curatedTweets}) => { const history = useHistory(); const switchToDisplay = () => { history.goBack(); } const topic = history.location.pathname.split('/')[2]; const tweets = (curatedTweets.groupedByNp || {})[topic];

Nun, da wir die Tweets mit diesem bestimmten Thema haben, ist das Anzeigen eigentlich ganz einfach:

 return ( <IonGrid> <IonRow> <IonCol> <IonButton color='primary' onClick={switchToDisplay}>Back</IonButton> </IonCol> </IonRow> <IonRow> <IonCol> <IonList> {(tweets || []).map((x, i) => <IonItem key={i}> <IonLabel className="ion-text-wrap"> <h2>{x.account}:</h2> <h3>{x.tweet}</h3> <p>({x.data.sentiment.toPrecision(2)})</p> </IonLabel> </IonItem>)} </IonList> </IonCol> </IonRow> </IonGrid> );

Speichern und ausführen, und die Dinge sollten gut aussehen.

Ausführen der App im Emulator

Um die App im Emulator auszuführen, führen wir einfach ein paar Ionic-Befehle aus, um die mobile Plattform hinzuzufügen und den Code zu kopieren, ähnlich wie wir die Dinge mit Cordova einrichten.

 ionic build # builds the app ionic cap add ios # adds iOS as one of the platforms, only have to run once ionic cap copy # copy the build over ionic cap sync # only need to run this if you added native plugins ionic cap open ios # run the iOS emulator

Und Sie sollten sehen, dass die App angezeigt wird.

Reagieren Sie auf die native Implementierung

Nativer Primer reagieren

React Native verfolgt einen ganz anderen Ansatz als die webbasierten Ansätze der vorherigen Abschnitte. React Native rendert Ihren React-Code als native Komponenten. Dies bringt mehrere Vorteile mit sich. Erstens ist die Integration mit dem zugrunde liegenden Betriebssystem viel tiefer, was es dem Entwickler ermöglicht, neue Smartphone-Funktionen und betriebssystemspezifische Funktionen zu nutzen, die möglicherweise nicht über Cordova/Capacitor verfügbar sind. Zweitens ist eine React Native-App im Allgemeinen schneller als eine, die mit Cordova geschrieben wurde, da es keine webbasierte Rendering-Engine in der Mitte gibt. Da React Native die Integration nativer Komponenten ermöglicht, können Entwickler schließlich eine viel feinere Kontrolle über ihre Anwendung ausüben.

Für unsere Anwendung verwenden wir die Logik aus den vorherigen Abschnitten und verwenden eine React Native-Komponentenbibliothek namens NativeBase, um unsere Benutzeroberfläche zu codieren.

Konfigurieren der App

Zuerst sollten Sie alle erforderlichen Komponenten von React Native gemäß den Anweisungen hier installieren.

Sobald React Native installiert ist, starten wir das Projekt:

 react-native init TwitterCurationRN

Lassen Sie das Setup-Skript laufen, und schließlich sollte der Ordner erstellt werden. Cd in den Ordner und führen Sie "react-native run-ios" aus, und Sie sollten sehen, dass der Emulator mit der Beispiel-App auftaucht.

Wir werden auch NativeBase installieren wollen, da dies unsere Komponentenbibliothek ist. Dazu führen wir Folgendes aus:

 npm install --save native-base react-native link

Wir wollen auch den React Native Stack Navigator installieren. Lass uns laufen:

 npm install --save @react-navigation/stack @react-navigation/native

Und

 react-native link cd ios pod-install cd

Um die Verknüpfung und Installation der nativen Plugins abzuschließen.

Router-Setup

Für das Routing verwenden wir den Stack-Navigator, den wir im obigen Schritt installiert haben.

Importieren Sie die Router-Komponenten:

 import { NavigationContainer } from '@react-navigation/native'; import {createStackNavigator} from '@react-navigation/stack';

Und jetzt erstellen wir einen Stack-Navigator:

 const Stack = createStackNavigator();

Ändern Sie den Inhalt der App-Komponente, um den Stack-Navigator zu verwenden:

 const App = () => { return ( <> <StatusBar bar /> <NavigationContainer> <Stack.Navigator initialRouteName="Entry"> <Stack.Screen name="Entry" component={Entry} /> </Stack.Navigator> </NavigationContainer> </> ); };

An dieser Stelle erhalten Sie eine Fehlermeldung, da der Eintrag noch nicht definiert ist. Lassen Sie uns ein Stub-Element definieren, nur um es glücklich zu machen.

Erstellen Sie einen Komponentenordner in Ihrem Projekt, erstellen Sie eine Datei mit dem Namen Entry.jsx und fügen Sie eine Stub-Komponente wie folgt hinzu:

 import React, {useState} from 'react'; import { Text } from 'native-base'; export default Entry = ({navigation}) => { return <Text>Entry</Text>; // All text must be wrapped in a <Text /> component or <TextView /> if you're not using NativeBase. }

Importieren Sie die Entry-Komponente in Ihre App, und sie sollte erstellt werden.

Jetzt können wir die Eingabeseite codieren.

Eingabeseite

Big-Picture-Plan

Wir werden eine Seite implementieren, die der oben implementierten sehr ähnlich ist, aber NativeBase-Komponenten verwendet. Die meisten der von uns verwendeten JavaScript- und React-APIs, wie Hooks und Fetch, sind alle noch verfügbar.

Der einzige Unterschied besteht in der Art und Weise, wie wir mit der Navigations-API arbeiten, die Sie später sehen werden.

UI-Komponenten

Die zusätzlichen NativeBase-Komponenten, die wir verwenden werden, sind Container, Content, Input, List, ListItem und Button. Diese haben alle Analoga in Ionic und Bootstrap React, und die Entwickler von NativeBase haben es für Leute, die mit diesen Bibliotheken vertraut sind, sehr intuitiv gemacht. Einfach so importieren:

 import { Container, Content, Input, Item, Button, List, ListItem, Text } from 'native-base';

Und die Komponente ist:

 return <Container> <Content> <Item regular> <Input placeholder='Input Handles Here' onChangeText={inputChange} value={input} /> <Button primary onPress={onAddClicked}><Text> Add </Text></Button> <Text> </Text> <Button success onPress={onPullClicked}><Text> Pull </Text></Button> </Item> <Item> <List style={{width: '100%'}}> {handles.map((item) => <ListItem key={item.key}> <Text>{item.key}</Text> </ListItem>)} </List> </Item> </Content> </Container>

Und jetzt implementieren wir die Zustands- und Ereignishandler:

 const [input, changeInput] = useState(''); const [handles, changeHandles] = useState([]); const inputChange = (text) => { changeInput(text); } const onAddClicked = () => { const newHandles = [...handles, {key: input}]; changeHandles(newHandles); changeInput(''); }

Und schließlich der API-Aufruf:

 const onPullClicked = () => { fetch('http://prismatic.pythonanywhere.com/get_tweets', { method: 'POST', mode: 'cors', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ accounts: handles.map(x => x.key) }) }).then(r=>r.json()).then(data => { navigation.navigate('SentimentDisplay', { data }); }) .catch(e => { console.log(e); }) }

Beachten Sie, dass diese Implementierung dieselbe ist wie in der NativeBase-Implementierung, außer dass wir auf eine andere Art und Weise navigieren. Der Stack-Navigator übergibt an seine Komponenten eine Requisite namens „Navigation“, die zum Navigieren zwischen Routen mit .navigate verwendet werden kann. Neben der einfachen Navigation können Sie auch Daten an die Zielkomponente übergeben. Wir werden diesen Mechanismus verwenden, um die Daten weiterzugeben.

Um die App zu kompilieren, müssen wir Entry noch auf die Navigationskomponente aufmerksam machen. Dazu müssen wir die Deklaration der Komponentenfunktion ändern:

 export default Entry = ({navigation}) => {

Speichern Sie jetzt, und Sie sollten die Seite sehen.

Sentimentsortierte Seite

Big-Picture-Plan

Wir werden die Stimmungsseite ähnlich wie in den vorherigen Abschnitten implementieren, aber wir werden die Seite etwas anders gestalten, und wir werden auch die Navigationsbibliothek anders verwenden, um den Rückgabewert des API-Aufrufs zu erhalten.

Da React Native kein CSS hat, müssen wir entweder ein StyleSheet-Objekt definieren oder die Stile einfach inline codieren. Da wir einen Teil des Stylings komponentenübergreifend gemeinsam nutzen werden, erstellen wir ein globales Stylesheet. Das machen wir nach der Routeneinstellung.

Da StackNavigator über eine integrierte Zurück-Navigationsschaltfläche verfügt, müssen wir keine eigene Zurück-Schaltfläche implementieren.

Routen-Setup

Die Routendefinition in StackNavigator ist sehr einfach. Wir erstellen einfach einen neuen namens Stack Screen und geben ihm die Komponente, ähnlich wie beim React-Router.

 <NavigationContainer> <Stack.Navigator initialRouteName="Entry"> <Stack.Screen name="Entry" component={Entry} /> <Stack.Screen name="SentimentDisplay" component={SentimentDisplay} /> </Stack.Navigator> </NavigationContainer>

Damit dies funktioniert, müssen wir natürlich eine Stub-Komponente in components/SentimentDisplay.js erstellen:

 import React from 'react'; import {Text} from 'native-base'; const SentimentDisplay = () => { return <Text>Sentiment Display</Text>; } export default SentimentDisplay;

Und importiere es:

 import SentimentDisplay from './components/SentimentDisplay';

Jetzt können wir das globale Stylesheet erstellen.

Globales Stylesheet

Erstellen Sie zunächst eine Datei mit dem Namen globalStyles.js. Importieren Sie dann die StyleSheet-Komponente aus React Native und definieren Sie die Stile:

 import {StyleSheet} from 'react-native'; export default StyleSheet.create({ tweet: {paddingTop: 5}, accountName: {fontWeight: '600'}, })

Und wir sind bereit, die Benutzeroberfläche zu codieren.

UI-Komponenten

Die UI-Komponente ist ziemlich vertraut, mit Ausnahme dessen, wie wir mit den Routen arbeiten. Wir möchten die spezielle Requisitennavigation und -route von StackNavigator verwenden, um den aktuellen Anwendungsstatus abzurufen und zur Themenanzeige zu navigieren, falls der Benutzer diese Seite sehen möchte.

Ändern Sie die Komponentendefinition, um auf die Navigationsstützen zuzugreifen:

 const SentimentDisplay = ({route, navigation}) => {

Und jetzt implementieren wir das Lesen des Anwendungsstatus und die Navigationsfunktion:

 const {params: {data}} = route; const viewByTopicClicked = () => { navigation.navigate('TopicDisplay', { data }); }

Importieren Sie die globalen Stile:

 import globalStyles from './globalStyles';

Und die Komponenten:

 import { View } from 'react-native'; import {List, Item, Content, ListItem, Container, Text, Button} from 'native-base';

Und zum Schluss die Komponenten:

 return <Container> <Content> <Item> <Button primary onPress={viewByTopicClicked}><Text>View By Topic</Text></Button> </Item> <Item> <List style={{width: '100%'}}> {data.sentimentSorted.map((item, i) => <ListItem key={i}> <View style={globalStyles.listItem}> <Text style={globalStyles.accountName}>{item.account}:</Text> <Text style={globalStyles.tweet}>{item.tweet} ({item.data.sentiment.toPrecision(2)})</Text> </View> </ListItem>)} </List> </Item> </Content> </Container>;

Speichern und versuchen Sie, einige Tweets abzurufen, und Sie sollten die Stimmungsanzeige sehen. Nun zur Themengruppierungsseite.

Themengruppierungsseite

Big-Picture-Plan

Die Themenanzeige ist wieder sehr ähnlich. Wir werden einen Handler-Builder verwenden, um eine Navigationsfunktion zu erstellen, um zur Anzeigeseite für ein bestimmtes Themenelement zu navigieren, und wir werden auch ein Stylesheet definieren, das für diese Seite spezifisch ist.

Eine neue Sache, die wir tun werden, ist die Implementierung einer TouchableOpacity, einer React Native-spezifischen Komponente, die ähnlich wie eine Schaltfläche funktioniert.

Routen-Setup

Die Routendefinition ist die gleiche wie zuvor:

 <Stack.Navigator initialRouteName="Entry"> <Stack.Screen name="Entry" component={Entry} /> <Stack.Screen name="SentimentDisplay" component={SentimentDisplay} /> <Stack.Screen name="TopicDisplay" component={TopicDisplay} /> </Stack.Navigator>

Die Stub-Komponente components/TopicDisplay.js:

 import React from 'react'; import {Text} from 'native-base'; const TopicDisplay = () => { return <Text>Topic Display</Text>; } export default TopicDisplay;

Und importiere es:

 import TopicDisplay from './components/TopicDisplay;

UI-Komponenten

Vieles davon wird Ihnen sehr bekannt vorkommen. Importieren Sie die Bibliotheksfunktionen:

 import { View, TouchableOpacity, StyleSheet } from 'react-native'; import {List, Item, Content, ListItem, Container, Text} from 'native-base';

Importieren Sie die globalen Stile:

 import globalStyles from './globalStyles';

Definieren Sie die benutzerdefinierten Stile:

 const styles = StyleSheet.create({ topicName: {fontWeight: '600'}, })

Definieren Sie die Navigationsstützen:

 export default TopicDisplay = ({route, navigation}) => {

Definieren Sie die Daten- und Aktionshandler. Beachten Sie, dass wir einen Handler-Builder verwenden, eine Funktion, die eine Funktion zurückgibt:

 const {params: {data}} = route; const specificItemPressedHandlerBuilder = (topic) => () => { navigation.navigate('TopicDisplayItem', { data, topic }); }

Und jetzt die Komponenten. Beachten Sie, dass wir eine TouchableOpacity verwenden, die einen onPress -Handler haben kann. Wir hätten auch TouchableTransparency verwenden können, aber die Click-and-Hold-Animation von TouchableOpacity war für unsere Anwendung besser geeignet.

 return <Container> <Content> <Item> <List style={{width: '100%'}}> {Object.keys(data.groupedByNp).map((topic, i) => <ListItem key={i}> <View style={globalStyles.listItem}> <TouchableOpacity onPress={specificItemPressedHandlerBuilder(topic)}> <Text style={styles.topicName}>{topic}</Text> </TouchableOpacity> </View> </ListItem>)} </List> </Item> </Content> </Container>;

Und das sollte es tun. Anwendung speichern und ausprobieren!

Gehen Sie nun auf die Themenanzeige-Elementseite.

Thema Anzeigeelementseite

Big-Picture-Plan

Die Seite „Topic Display Item“ ist sehr ähnlich und alle Eigenheiten werden in den anderen Abschnitten berücksichtigt, sodass es von hier aus reibungslos weitergehen sollte.

Routen-Setup

Wir fügen die Routendefinition hinzu:

 <Stack.Screen name="TopicDisplayItem" component={TopicDisplayItem} />

Fügen Sie den Import hinzu:

 import TopicDisplayItem from './components/TopicDisplayItem';

Und erstellen Sie die Stub-Komponente. Statt nur einer bloßen Komponente importieren wir auch die NativeBase-Komponenten, die wir verwenden werden, und definieren die Route-Requisiten:

 import React from 'react'; import {View} from 'react-native'; import {List, Item, Content, ListItem, Container, Text} from 'native-base'; import globalStyles from './globalStyles'; const TopicDisplayItem = ({route}) => { const {params: {data, topic}} = route; return <Text>Topic Display Item</Text>; } export default TopicDisplayItem;

UI-Komponenten

Die UI-Komponente ist recht einfach. Wir haben es schon einmal gesehen und wir implementieren keine benutzerdefinierte Logik. Also, lass es uns einfach angehen! Tief durchatmen…

 return <Container> <Content> <Item> <List style={{width: '100%'}}> {data.groupedByNp[topic].map((item, i) => <ListItem key={i}> <View style={globalStyles.listItem}> <Text style={globalStyles.accountName}>{item.account}:</Text> <Text style={globalStyles.tweet}>{item.tweet} ({item.data.sentiment.toPrecision(2)})</Text> </View> </ListItem>)} </List> </Item> </Content> </Container>;

Speichern Sie, und wir sollten startklar sein! Jetzt können wir die App im Emulator ausführen … Moment, haben wir das nicht schon?

Ausführen der App

Nun, da Sie mit React Native arbeiten, führen Sie die App bereits im Emulator aus, sodass dieser Teil bereits erledigt ist. Dies ist eines der großartigen Dinge an der Entwicklungsumgebung von React Native.

Wütend! Damit sind wir mit dem Programmierteil dieses Artikels fertig. Mal sehen, was wir über die Technologien gelernt haben.

Vergleich der Technologien

Cordoba: Vor- und Nachteile

Das Beste an Cordova ist die schiere Geschwindigkeit, mit der ein erfahrener Webentwickler etwas Funktionales und einigermaßen Vorzeigbares programmieren kann. Fähigkeiten und Erfahrungen in der Webentwicklung lassen sich leicht übertragen, da Sie schließlich eine Web-App programmieren. Der Entwicklungsprozess ist schnell und einfach, und der Zugriff auf die Cordova-API ist ebenfalls einfach und intuitiv.

Die Nachteile der direkten Verwendung von Cordova ergeben sich hauptsächlich aus der übermäßigen Abhängigkeit von Webkomponenten. Benutzer erwarten bei der Verwendung mobiler Apps eine bestimmte Benutzererfahrung und ein bestimmtes Schnittstellendesign, und wenn sich eine Anwendung wie eine mobile Website anfühlt, kann die Erfahrung etwas verwirrend sein. Darüber hinaus müssen die meisten in Apps integrierten Funktionen, wie z. B. Übergangsanimationen und Navigationsprogramme, manuell implementiert werden.

Ionic: Vor- und Nachteile

Das Beste an Ionic war, wie viele mobilzentrierte Funktionen ich „kostenlos“ bekam. Indem ich so codierte, wie ich eine Webanwendung codiert hätte, konnte ich eine App erstellen, die viel mobilfreundlicher aussieht als die einfache Verwendung von Cordova und React-Bootstrap. Es gab Navigationsanimationen, Schaltflächen mit nativ aussehenden Stilen und viele Benutzeroberflächenoptionen, die die Benutzererfahrung sehr reibungslos machten.

Der Nachteil der Verwendung von Ionic wurde teilweise durch seine Stärken verursacht. Erstens war es manchmal schwierig, sich vorzustellen, wie sich die App in verschiedenen Umgebungen verhalten würde. Nur weil die App in eine Richtung aussah, bedeutete das nicht, dass die gleiche UI-Platzierung in einer anderen Umgebung gleich aussehen würde. Zweitens sitzt Ionic auf vielen Teilen der zugrunde liegenden Technologien, und der Zugang zu einigen der Komponenten erwies sich als schwierig. Schließlich ist dies spezifisch für Ionic-React, aber da Ionic zuerst für Angular entwickelt wurde, schienen viele Ionic-React-Funktionen weniger Dokumentation und Unterstützung zu haben. Das Ionic-Team scheint jedoch sehr aufmerksam auf die Bedürfnisse der React-Entwickler zu sein und liefert schnell neue Funktionen.

Native reagieren: Vor- und Nachteile

React Native hatte eine sehr reibungslose Benutzererfahrung bei der Entwicklung auf Mobilgeräten. Durch die direkte Verbindung mit dem Emulator war es kein Geheimnis, wie die Anwendung aussehen würde. Die webbasierte Debugger-Schnittstelle war äußerst hilfreich bei der übergreifenden Anwendung von Debugging-Techniken aus der Welt der Webanwendungen, und das Ökosystem ist ziemlich robust.

Der Nachteil von React Native liegt in seiner Nähe zur nativen Schnittstelle. Viele DOM-basierte Bibliotheken konnten nicht verwendet werden, was bedeutete, dass neue Bibliotheken und Best Practices erlernt werden mussten. Ohne die Vorteile von CSS war das Styling der Anwendung etwas weniger intuitiv. Schließlich gibt es mit vielen neuen Komponenten, die es zu lernen gilt (z. B. View statt div, Text-Komponente, die alles umschließt, Buttons vs. TouchableOpacity vs. TouchableTransparency usw.), am Anfang eine kleine Lernkurve, wenn jemand dazu kommt Reagieren Sie auf die Welt der Ureinwohner mit wenig Vorkenntnissen der Mechanik.

Wann Sie die einzelnen Technologien verwenden sollten

Da Cordova, Ionic und React Native alle sehr starke Vor- und Nachteile haben, hat jede Technologie einen Kontext, in dem sie die beste Produktivität und Leistung erzielen würde.

Wenn Sie bereits eine bestehende Anwendung haben, die Web-First ist und eine starke Markenidentität rund um das UI-Design und das allgemeine Erscheinungsbild aufweist, wäre Cordova Ihre beste Option, die Ihnen Zugriff auf die nativen Funktionen des Smartphones bietet, während Sie die meisten davon wiederverwenden können Webkomponenten und bewahren dabei Ihre Markenidentität. Für relativ einfache Anwendungen, die ein responsives Framework verwenden, können Sie möglicherweise eine mobile App mit sehr wenigen erforderlichen Änderungen erstellen. Ihre Anwendung sieht jedoch weniger wie eine App und eher wie eine Webseite aus, und einige der Komponenten, die Benutzer von einer mobilen App erwarten, werden separat codiert. Daher empfehle ich Cordova in Fällen, in denen Sie in einem Web-First-Projekt die Anwendung auf Mobilgeräte portieren.

Wenn Sie anfangen, eine neue Anwendung mit einer App-First-Philosophie zu programmieren, die Fähigkeiten Ihres Teams jedoch hauptsächlich in der Webentwicklung liegen, empfehle ich Ionic. Mit der Ionic-Bibliothek können Sie schnell Code schreiben, der nativen Komponenten ähnelt und sich anfühlt, während Sie Ihre Fähigkeiten und Instinkte als Webentwickler anwenden können. Ich habe festgestellt, dass die Best Practices für die Webentwicklung problemlos auf die Entwicklung mit Ionic angewendet werden können und dass das Styling mit CSS nahtlos funktioniert. Darüber hinaus sieht die mobile Version der Website viel nativer aus als eine Website, die mit einem responsiven CSS-Framework codiert wurde. Bei einigen Schritten auf dem Weg stellte ich jedoch fest, dass die React-Ionic-Native-API-Integration einige manuelle Anpassungen erfordert, die sich als zeitaufwändig erweisen könnten. Daher empfehle ich Ionic in Fällen, in denen Ihre Anwendung von Grund auf neu entwickelt wird und Sie eine erhebliche Menge an Code zwischen einer mobilfähigen Webanwendung und einer mobilen Anwendung teilen möchten.

Wenn Sie eine neue Anwendung mit einer implementierten nativen Codebasis programmieren, sollten Sie React Native ausprobieren. Auch wenn Sie keinen nativen Code verwenden, könnte dies auch die beste Option sein, wenn Sie bereits mit React Native vertraut sind oder wenn Ihr Hauptanliegen eher die mobile Anwendung als eine hybride Anwendung ist. Nachdem ich die meisten meiner Front-End-Entwicklungsbemühungen auf die Webentwicklung konzentriert hatte, stellte ich zunächst fest, dass der Einstieg in React Native aufgrund der Unterschiede in der Komponentenorganisation und den Codierungskonventionen eine größere Lernkurve hatte als bei Ionic oder Cordova. Sobald diese Nuancen jedoch erlernt sind, ist die Codierungserfahrung ziemlich reibungslos, insbesondere mit Hilfe einer Komponentenbibliothek wie NativeBase. Angesichts der Qualität der Entwicklungsumgebung und der Kontrolle über die Anwendung würde ich React Native als Tool Ihrer Wahl empfehlen, wenn das Frontend Ihres Projekts hauptsächlich eine mobile Anwendung ist.

Zukünftige Themen

Eines der Themen, für das ich keine Zeit hatte, war der einfache Zugriff auf native APIs wie Kamera, Geolokalisierung oder biometrische Authentifizierung. Einer der großen Vorteile der mobilen Entwicklung ist die Zugänglichkeit eines reichhaltigen API-Ökosystems, das im Allgemeinen nicht über den Browser zugänglich ist.

In zukünftigen Artikeln möchte ich untersuchen, wie einfach es ist, diese nativen API-fähigen Anwendungen mit verschiedenen plattformübergreifenden Technologien zu entwickeln.

Fazit

Heute haben wir eine Twitter-Kurations-App mit drei verschiedenen plattformübergreifenden mobilen Entwicklungstechnologien implementiert. Ich hoffe, dies hat Ihnen ein gutes Gefühl dafür gegeben, wie jede Technologie ist, und Sie dazu inspiriert, Ihre eigene React-basierte Anwendung zu entwickeln.

Vielen Dank fürs Lesen!