
Das Vergleichen von Frameworks ist eine sehr undankbare Aufgabe, die Vorlieben der Entwickler sind unterschiedlich, die Technologien ändern sich sehr schnell. Zu schnell. Dieser Artikel ist veraltet, noch bevor ich auf die Schaltfläche "Veröffentlichen" klicke.
Es gab Versuche, zum Beispiel vor etwa fünf Jahren zu vergleichen, dass die Jungs (Colin Eberhardt und Chris Price) eine Reihe von Entwicklern dazu inspirierten, eine Anwendung für die Suche nach Immobilien gemäß klar zusammengestellter TK zu erstellen. Die Idee ist cool, wir haben sogar teilgenommen und eine Version dieser Anwendung auf
DevExtreme erstellt . In Bezug auf die Unterstützung ist ein solches Projekt die Hölle, und jetzt stellt das
Property Cross- Projekt eine bestimmte historische Schicht dar, die Nostalgie und warme Gefühle hervorruft, aber kaum von praktischem Nutzen ist.
Wenn wir nur die js-Welt nehmen, das heißt, ein ziemlich lebhaftes
todomvc- Projekt, das nur den js-Teil vergleicht, ohne in ein Handy, einen Desktop oder eine Anwendung zu packen. Das Projekt ist lebhaft und wird unterstützt. Höchstwahrscheinlich gibt es immer noch sehr coole Beispiele, die wir bei der Vorbereitung des Artikels bei Google nicht bemerkt haben, aber wir werden uns darüber nicht aufregen.
Unser Experiment ist weniger ehrgeizig und zeigt nur den aktuellen Teil der Technologien, auch nur einen kleinen Teil davon. Hier ist ein Link zum
ersten und
zweiten Artikel des Experiments.
Weiterführende Literatur ist der dritte Artikel darüber, wie man eine Anwendung auf React Native gemäß TK erstellt. Es ist Hunderten und vielleicht Tausenden anderer Nacherzählungen von Dokumentationen zum Erstellen einer Anwendung auf React Native sehr ähnlich. Lieber Leser, ich habe Sie gewarnt, mein Gewissen ist klar.
Erinnere dich an TK
Im Allgemeinen kann es im ersten Artikel vollständig eingesehen werden. Aber ich werde ein Bild hinzufügen, was am Ende resultieren sollte. Es gibt nur wenige Bilder.

Eine Prise Ausrüstung. Was ist React Native?
React Native ist ein Framework zum Erstellen plattformübergreifender mobiler Anwendungen von Facebook. Wie bei der „normalen“ Reaktion für das Web wird die UI-Anwendung aus Bausteinen zusammengesetzt - Komponenten, die auf Änderungen ihres Status (Status) und der an sie übergebenen Eigenschaften (Requisiten) reagieren, aber im Gegensatz zum Web in native Steuerelemente gerendert werden.
Im Idealfall werden die Prinzipien der Immunität und der reinen Funktionen verwendet, was die Einfachheit und Isolation der Tests gewährleistet. Und hier ist anzumerken, dass React selbst sehr einfach ist und diese Einfachheit in den mobilen Teil einfließt.
Zusätzliche Add-Ons in nativem und JS-Code gleichen den Unterschied zwischen Plattformen nach Möglichkeit aus. Tatsächlich bietet React Native eine gewisse Vereinheitlichung der Eigenschaften für die Komponente in jedem Betriebssystem.
Beispielsweise sind ScrollView und HorizontalScrollView zwei verschiedene Komponenten in Android. Und in iOS UIScrollView, das sowohl horizontales als auch vertikales Scrollen unterstützt. In React Native verwenden wir den folgenden plattformübergreifenden Code:
<ScrollView horizontal={true}/>
Mit einem kompetenten Ansatz erhalten wir eine „ehrliche“ native Anwendung, die auf iOS und Android ausgeführt wird.
In einer idealen Welt müssen Sie bei der Entwicklung in React Native nicht in Java oder Objective-C schreiben. Es gibt jedoch eine solche Möglichkeit, wenn Sie eine Komponente implementieren müssen, die über die Funktionen von React Native hinausgeht.
Die Entwickler von Airbnb haben viel damit gespielt, und wir können sehen, dass viele würdige Implementierungen in der Community reagieren, die sich zuvor in ihrem Repository befanden.
Lottie ist beispielsweise eine Bibliothek zum Importieren von Animationen aus Adobe After Effects oder
plattformübergreifenden Karten .
JS-Code in der Anwendung wird auf der
JavaScriptCore- Engine ausgeführt. Die Kommunikation zwischen nativem Code und JS erfolgt über eine asynchrone Brücke (Bridge), mit der Sie Eigenschaften (Requisiten) übertragen, Ereignisse (Ereignisse) und Rückrufe auslösen können.

Bild aus einer ausgezeichneten
React Made Native Easy- Dokumentation. (Sehr zu empfehlen zu lesen.)
Während des Erstellungsprozesses wird zum Konvertieren von JS-Code ein neuartiges Babel verwendet. Auf diese Weise können Sie die neue ES6-Syntax sowie einige ES8-Funktionen (z. B. asynchrones Warten) verwenden. Wenn Sie, mein lieber Leser, ein js-Entwickler sind, verstehen Sie, wie gut es ist, wenn es einen Spread-Operator gibt, und wie schlecht es ist, wenn es nicht ist.
Für das Seitenlayout wird die Flexbox-Technologie verwendet, die von der plattformübergreifenden Yoga-Engine implementiert wird. Es hat Unterschiede zur Browser-Flexbox, aber sie sind unbedeutend und beziehen sich hauptsächlich auf Standardeinstellungen. Natürlich gibt es Nuancen, aber Sie werden Glück haben und alles wird nur gemäß der Dokumentation sein.
Vorbereiten und Bereitstellen des Stapels. Röhrenanschluss
Um mit RN arbeiten zu können, benötigen wir
Node.js und den mitgelieferten npm-Paketmanager. Es ist nicht erforderlich, aber es ist sehr wünschenswert, die
Expo- Anwendung auf Ihrem Gerät zu installieren. Damit können Sie unser Projekt auf Ihrem Telefon starten und eine iOS-Anwendung erstellen und ausführen, wenn Sie nicht über macOS verfügen.
Lassen Sie uns eine neue Anwendung erstellen. Verwenden Sie dazu das Paket
create-react-native-app .
Führen Sie im Terminal Folgendes aus:
npm install -g create-react-native-app create-react-native-app notes cd notes npm run start
Scannen Sie den QR-Code mit Expo oder geben Sie einen Link vom Terminal aus ein oder senden Sie den Link sogar direkt vom Terminal an Ihr Telefon.
Ich habe im Allgemeinen den Verdacht, dass die Cli-Entwickler für React Native einen grauhaarigen alten Mann hatten, der schurkenhaftes Spielzeug ohne UI gefunden hat, wenn es nur ein Terminal gibt, und statt einer Top-End-Grafikkarte nur Ihre Vorstellungskraft.

In der Zwischenzeit haben wir die Anwendung „Hello World“ erstellt und gestartet.
Und die ganze "Hallo Welt" -a ist nicht genug. TK analysieren
Entsprechend der Arbeitsaufstellung wird die Datenstruktur der Anwendung sein
Note: { userName: string, avatar: string, editTime: string, text: string } Project: { name: string, notes: Array<Note> } Projects: Array<Project>
Um mit solchen Daten zu arbeiten, würde ich eine sehr modische Lösung verwenden, die auf CQRS basiert. Dies würde die Wahrung der Datenintegrität ermöglichen, eine hohe Lesegeschwindigkeit mit der Möglichkeit, Projektionen neu anzuordnen, sowie eine schnelle Bereitstellung in der Cloud mit einem einzigen Befehl. Wie
Resolve , das von unseren Kollegen entwickelt wird.
Aber ich nehme es nicht an, wir haben ein einfaches Experiment ohne Backend. Und der Einfachheit halber werde ich die
Flussarchitektur verwenden , insbesondere ihre Implementierung -
Redux . Daten aus dem Anwendungsstatus werden als Requisiten an die Komponenten gesendet. Komponenten können Aktionen aufrufen, um Daten zu aktualisieren.
Die Anwendung wird 3 Bildschirme haben, alle gemäß ToR:
- Liste der Projekte - Projekte,
- detaillierte Projektseite mit einer Liste von Notizen - Projekt,
- detaillierte Notizseite - Hinweis
Für die Navigation zwischen den Bildschirmen verwende ich die Standardbibliothek für die
Reaktionsnavigation . Die Zahlen in der Nähe des Diagramms auf der Bibliotheksseite geben an, wie oft es pro Woche heruntergeladen wird. Jetzt gibt es ungefähr 100.000 pro Woche. Es ist gut, dass ich nicht der einzige war, der eine solche Bibliothek für die Navigation ausgewählt hat. Und ja, Sie können die Ziffern anderer npm-Pakete sehen, die ich in diesem Artikel angegeben habe, um die Anzahl der Benutzer dieser Technologie zu einem bestimmten Zeitpunkt grob zu verstehen.
Erstellen Sie eine Anwendung
Für React Native ist die App-Komponente aus der Datei App.js der Einstiegspunkt in die Anwendung.
export default class App extends Component { render() { return ( <Provider store={store}> <Navigator /> </Provider> ) } }
Speichern mit Daten und Anwendungsstatus wird von der Provider-Komponente aus der React-Redux-Bibliothek verbunden. Dies bietet eine Datenweiterleitung für verschachtelte Komponenten.
Erstellen Sie einen Navigator für Übergänge zwischen Bildschirmen in der Anwendung. Es spiegelt deutlich die im Experiment deklarierte Struktur der Anwendung wider und zeichnet animierte Übergänge zwischen Bildschirmen für jede Plattform.
const Navigator = createStackNavigator({ Projects: { screen: Projects }, Project: { screen: Project }, Note: { screen: Note } })
Navigator-Bildschirme sind Komponenten - Container. Sie erhalten Daten aus dem Anwendungsstatus.
Projektliste - Projekte
Auf dem Bildschirm mit einer Liste von Projekten befindet sich eine Liste und eine Schaltfläche zum Hinzufügen eines Projekts - in der Kopfzeile des Fensters rechts. Wir werden ein neues Projekt auf dem Projektbildschirm erstellen.
Für die Navigation verwenden wir das Navigationsobjekt, das die übergeordnete Komponente - den Navigator - an die Requisiten übergeben hat.
export class Projects extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <AddButton onPress={() => navigation.navigate('Project')} /> ) }) navigateProject = project => { this.props.navigation.navigate('Project', { projectId: project.id, name: project.name }) } render() { return ( <ProjectList projects={this.props.projects} onPressProject={this.navigateProject} /> ) } }
Um die Liste der Projekte anzuzeigen, verwenden wir FlatList - eine plattformübergreifende Liste mit Virtualisierung:
export class ProjectList extends PureComponent { static propTypes = { projects: ProjectsType, onPressProject: PropTypes.func } renderItem = ({ item }) => ( <ProjectListItem project={item} onPressProject={this.props.onPressProject} /> ) render() { return ( <FlatList data={this.props.projects} keyExtractor={item => item.id} renderItem={this.renderItem} /> ) } }
Für jedes Element legen wir einen eindeutigen Schlüssel fest - hier haben wir die ID des Elements. Dies ist erforderlich, damit die Reaktion zwischen Elementen in der Liste unterscheiden und nur diejenigen aktualisieren kann, die sich geändert haben.
Fügen Sie dem Listenelement eine Komponente hinzu.
export class ProjectListItem extends PureComponent { static propTypes = { project: ProjectType, onPressProject: PropTypes.func } onPressProject = () => { const { project, onPressProject } = this.props onPressProject(project) } render() { return ( <TouchableOpacity onPress={this.onPressProject}> <View style={styles.project}> <Text style={styles.name}>{this.props.project.name}</Text> </View> </TouchableOpacity> ) } }
TouchableOpactity - ein Wrapper, der auf Klicks reagiert. Wenn Sie darauf klicken, wird die verschachtelte Komponente transparenter.
Ansicht - Analogon von div für Web - Grundkomponente des Markups.
Text - ein Container für Text.
Stile hinzufügen:
const styles = StyleSheet.create({ project: { paddingVertical: 30, paddingHorizontal: 15, backgroundColor: 'white', borderBottomWidth: StyleSheet.hairlineWidth, borderColor: 'gray' }, name: { fontSize: 16 } })
Die Stilsyntax ähnelt CSS. Der Hauptunterschied besteht darin, dass Sie nur die Komponente selbst stilisieren können (z. B. können Sie die Schriftgröße nicht für die gesamte Anwendung festlegen, sondern nur für eine bestimmte Textkomponente).

Detaillierte Projektseite mit einer Liste von Notizen - Projekt
Erstellen Sie auf ähnliche Weise eine detaillierte Seite. Die Unterschiede bestehen nur bei Vorhandensein eines Titels im Navigator und zusätzlicher Eingabe. Legen Sie im Navigator den Titel fest - den Namen des Projekts. Wenn die Projekt-ID nicht angegeben ist, bieten wir an, den Namen des Projekts einzugeben und ein neues zu erstellen.
export class Project extends PureComponent { static navigationOptions = ({ navigation }) => { const projectId = navigation.getParam('projectId') return { title: navigation.getParam('name', ''), headerRight: ( <AddButton onPress={() => navigation.navigate('Note', { projectId })} /> ) } } removeNote = noteId => { const { projectId, removeNote } = this.props removeNote(projectId, noteId) } navigateNote = noteId => { const { projectId, navigation } = this.props navigation.navigate('Note', { noteId, projectId }) } createProject = name => { const newProjectId = shortid.generate() this.props.navigation.setParams({ projectId: newProjectId, name }) this.props.addProject(newProjectId, name) } render() { const { projectId, project } = this.props if (!projectId) { return ( <ProjectNameInput onSubmitEditing={this.createProject} /> ) } return ( <NoteList notes={project.notes} onNavigateNote={this.navigateNote} onRemoveNote={this.removeNote} /> ) } }
Die Projektseite ist eine Liste von Notizen. Laut ToR gibt es für jede Note ein Kontextmenü zum Bearbeiten und Löschen. Sie können die Notiz auch mit einem Wisch löschen. In React Native gibt es eine separate Liste mit der Möglichkeit zu wischen - SwipeableFlatList.
<SwipeableFlatList data={this.props.notes} bounceFirstRowOnMount={false} keyExtractor={item => item.id} maxSwipeDistance={MAX_SWIPE_DISTANCE} renderQuickActions={this.renderQuickActions} renderItem={this.renderItem} />
Wenn Sie eine Notiz löschen, werden Sie um Bestätigung gebeten. Dazu rufen wir den Standardsystem-Alert auf
onRemoveNote = noteId => { Alert.alert( 'Remove Note', 'Do you want to remove note ?', [ { text: 'Cancel', onPress: () => {}}, { text: 'Remove', onPress: () => this.props.onRemoveNote(noteId) } ] ) }

Es gibt einen interessanten Punkt für das Kontextmenü. Im Gegensatz zur Warnung unterscheidet sich die Implementierung in RN für Android und iOS.
Verwenden Sie für Android das Popup-Menü
showPopupMenu = () => { const button = findNodeHandle(this._buttonRef) UIManager.showPopupMenu( button, [ 'Edit', 'Delete' ], e => console.error(e), (e, i) => this.onPressMenu(i) ) }
Für iOS - ActionSheet
showActionSheet = () => { ActionSheetIOS.showActionSheetWithOptions({ options: [ 'Edit', 'Delete', 'Cancel' ], destructiveButtonIndex: 1, cancelButtonIndex: 2 }, this.onPressMenu ) }
Es gibt verschiedene Möglichkeiten, plattformspezifischen Code aufzuteilen. Wir werden das Platform-Objekt verwenden.
onOpenMenu = Platform.select({ android: this.showPopupMenu, ios: this.showActionSheet })

Detaillierte Notizseite - Hinweis
Die Notizseite ist auch ziemlich primitiv. Im Gegensatz zu den vorherigen verwenden wir den Status, um Zwischenergebnisse für Benutzereingaben zu speichern.
export class Note extends PureComponent { static navigationOptions = ({ navigation }) => ({ headerRight: ( <SaveButton onPress={navigation.getParam('onSaveNote')} /> ) }) state = { noteText: '' } componentDidMount() { this.props.navigation.setParams({ onSaveNote: this.onSaveNote }) } onSaveNote = () => { Keyboard.dismiss() const { projectId, noteId, note, navigation, addNote, editNote } = this.props const { noteText } = this.state if (!noteId) { const newNoteId = shortId.generate() navigation.setParams({ noteId: newNoteId }) addNote(projectId, newNoteId, noteText) } else if (noteText && noteText !== note.text) { editNote(projectId, noteId, noteText) } } onChangeNote = noteText => { this.setState({ noteText }) } render() { const initialTextValue = this.props.note ? this.props.note.text : '' const noteText = this.state.noteText || initialTextValue return ( <NoteDetail noteText={noteText} onChangeNoteText={this.onChangeNote} /> ) } }
Der detaillierte Bildschirm der Notiz - die klassische „alberne“ Komponente - berichtet über die Textänderung nach oben und zeigt den Text an, den die Eltern an sie übergeben
export class NoteDetail extends PureComponent { static propTypes = { noteText: PropTypes.string, onChangeNoteText: PropTypes.func } render() { const { noteText, onChangeNoteText } = this.props return ( <View style={styles.note}> <TextInput multiline style={styles.noteText} value={noteText} placeholder="Type note text here ..." underlineColorAndroid="transparent" onChangeText={onChangeNoteText} /> </View> ) } }

Insgesamt haben wir die Bewerbung wie in TK erhalten. Das Experiment ist abgeschlossen. Der Anwendungscode kann im allgemeinen
Repository angezeigt werden
Insgesamt, Vor- und Nachteile von React Native
Vorteile:
React Native ist Entwicklern, die mit React und dem Node.js- und npm-Framework vertraut sind, vertraut und verständlich. Es ist möglich, alle Ansätze und Bibliotheken wie für die übliche Reaktion zu verwenden.
Eine große Anzahl von js-Paketen von npm. Höchstwahrscheinlich wurden die meisten Standardaufgaben bereits gelöst und möglicherweise unter einer MIT-Lizenz.
Große Gemeinschaft. Sowohl einzelne Entwickler als auch große Unternehmen haben RN für die Entwicklung verwendet und verwenden es weiterhin.
Viele vorgefertigte Sätze von UI-Komponenten wie
NativeBase ,
React Native Elements und Bibliotheken großer Unternehmen wie Facebook, Airbnb und Wix.com.
Klares Toolkit für die bequeme Anwendungsentwicklung von Hello World zu
Instagram .
Nachteile:
Die Anwendung startet langsamer als die native und es gibt einige Schwierigkeiten beim Debuggen. JS-Code in und ohne Debugger läuft auf verschiedenen Engines. Airbnb hat in einer
Reihe von Artikeln sehr gut über dieses Problem geschrieben, warum sie React Native in der Entwicklung aufgegeben haben.
Da das Toolkit aus vielen Paketen besteht, die separat entwickelt werden, besteht die Möglichkeit eines Versionskonflikts und einer Unterbrechung.
Nicht alles kann ohne nativen Code gemacht werden. Wenn Sie Änderungen am nativen Code vornehmen, verlieren Sie die Möglichkeit, Expo zu verwenden, und zwingen sich, die Anwendung mit nativen Standardentwicklungstools zu erstellen.
Vielen Dank an
Mirimon und
HeaTTheatR für die Einladung zur Teilnahme an diesem Experiment. Es war aufregend. Zuletzt eine Stimme hinzufügen.