Slide 1

Slide 1 text

Flutter or React Native a cross-platform dilemma Marco Gomiero

Slide 2

Slide 2 text

WHO I AM Mobile & Data Engineer @ Uniwhere MARCO GOMIERO COMPUTER ENGINEER Co-Leader @ GDG Venezia

Slide 3

Slide 3 text

LET’S GET IN TOUCH! twitter.com/marcoGomier MARCO GOMIERO COMPUTER ENGINEER github.com/prof18 marco.gomiero.93[at]gmail[dot]com marcogomiero.com

Slide 4

Slide 4 text

Disclaimer

Slide 5

Slide 5 text

Background

Slide 6

Slide 6 text

Background Flutter React Native

Slide 7

Slide 7 text

Agenda • History • Language • UI • Under the hood • Example • Conclusions

Slide 8

Slide 8 text

History JANUARY 2015 First public preview MAY 2015 Open sourced and launched officially SUMMER 2013 First version developed during an internal hackathon 2013 2015 2015 React Native

Slide 9

Slide 9 text

History JANUARY 2015 First public preview MAY 2015 Open sourced and launched officially SUMMER 2013 First version developed during an internal hackathon 2013 2015 2015 Flutter React Native MAY 2017 Alpha Release DECEMBER 2018 First 1.0 version APRIL 2015 Unveiled at Dart Dev Summit 2015 2018 2017

Slide 10

Slide 10 text

Trends React Native Flutter UPDATE Last update: September 2019

Slide 11

Slide 11 text

Trends Last update: September 2019

Slide 12

Slide 12 text

LANGUAGE

Slide 13

Slide 13 text

React Native • Javascript • ☠ for Object Oriented Devs: • Type Conversion • Sometimes silently fails • Prototype based inheritance • Ecosystem Confusion

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

Flutter • Dart, invented by Google in 2011 • Object Oriented friendly • e.g strongly typed but type can be inferred • Flat learning curve for OO devs • Mobile -> compiles to ARM and x86 code • Web -> transpiles to Javascript

Slide 16

Slide 16 text

!crusade It’s not a language crusade, just my experience

Slide 17

Slide 17 text

UI

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } });

Slide 20

Slide 20 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } }); // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 21

Slide 21 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } }); // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 22

Slide 22 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } });

Slide 23

Slide 23 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } });

Slide 24

Slide 24 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } });

Slide 25

Slide 25 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } });

Slide 26

Slide 26 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } }); Components • Basic UI building blocks • Fit together to form a custom component • Domain specific language called JSX • Customisable with CSS • Or better “usually match how CSS works on the web”

Slide 27

Slide 27 text

https://facebook.github.io/react-native/docs/components-and-apis.html

Slide 28

Slide 28 text

// React Native import React from "react"; import { StyleSheet, Text, View } from "react-native"; export default class App extends React.Component { render() { return ( Hello world! ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: "#fff", alignItems: "center", justifyContent: "center" } }); // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 29

Slide 29 text

// Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 30

Slide 30 text

// Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 31

Slide 31 text

// Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }

Slide 32

Slide 32 text

// Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child: Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); } • Basic UI building blocks • Takes inspiration from RN • Everything is a Widget Widgets

Slide 33

Slide 33 text

Structural Element (Button, Menu …)

Slide 34

Slide 34 text

Stylistic Element (Font, Color Scheme ..)

Slide 35

Slide 35 text

Aspect of Layout (Padding, Align ..)

Slide 36

Slide 36 text

https://flutter.io/docs/development/ui/widgets

Slide 37

Slide 37 text

Components vs Widgets: Summary • React Native: jumps from Javascript to JSX • Flutter: remains in the Dart context • Possibility of UI modularisation

Slide 38

Slide 38 text

Components vs Widgets: Summary • React Native: jumps from Javascript to JSX • Flutter: remains in the Dart context • Possibility of UI modularisation

Slide 39

Slide 39 text

State Management • You should do it! • Separation of presentation logic from business logic • Data sync from different components/widget
 
 … • React Native: “Naive method”, Redux, .. • Flutter: “Naive method”, Scoped Model, BLoC, Redux, ..

Slide 40

Slide 40 text

State Management - Flutter • https://www.youtube.com/watch?v=PLHln7wHgPE • https://www.youtube.com/watch?v=RS36gBEp8OI • https://www.youtube.com/watch?v=d_m5csmrf7I • http://fluttersamples.com/

Slide 41

Slide 41 text

Declarative UI • Imperative style: retrieve an instance from the view owner and update it based on the new state • Describe the current UI state and the framework manages state changes

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

Jetpack Compose https://developer.android.com/jetpack/compose

Slide 44

Slide 44 text

Jetpack Compose • Kotlin based • Composable function that transform application data to UI hierarchy import androidx.compose.* import androidx.ui.core.* @Composable fun Greeting(name: String) { Text ("Hello $name!") }

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

https://developer.apple.com/xcode/swiftui/

Slide 47

Slide 47 text

https://developer.apple.com/xcode/swiftui/

Slide 48

Slide 48 text

UNDER THE HOOD

Slide 49

Slide 49 text

React Native • Core: an infrastructure, aka “Bridge” built at runtime • It lets native code call JS and viceversa • Your code run inside a JS Virtual Machine: JavaScriptCore • Event driven

Slide 50

Slide 50 text

• Event driven Event Serialized Payload Process Event Process Command Serialized Response Call native methods App opening [1, 1, [‘My App’, {}]] [[2, 3, [2, ‘View’, {…}]],
 [2, 3, [3, ‘View’, {…}]]] val view = View()
 val view = TextView() Render new Views

Slide 51

Slide 51 text

• Calls passed between JS to Native in a “batched asynchronous way” • quequed in the MessageQueue -> flushed every 5 ms by default • Event driven

Slide 52

Slide 52 text

New RN Architecture • React Native team is working on a new architecture: Fabric • High priority UI updates synchronously • No more bridge and serialisation • JSI (JavaScript Interface) between JS and Native Code https://www.youtube.com/watch?v=UcqRXTriUVI

Slide 53

Slide 53 text

Flutter • Dart code compiled into native, ARM and x86 libraries • Widgets are managed and rendered using a C++ engine Framework (Dart) Engine (C++) Skia Dart Text Material Cupertino Widgets Rendering Animation Painting Gestures Foundation

Slide 54

Slide 54 text

Flutter • Dart code compiled into native, ARM and x86 libraries • Widgets are managed and rendered using a C++ engine • All elements are rendered with Skia, a 2-d graphics library • Pro: take advantage of the GPU • Cons: app size is larger

Slide 55

Slide 55 text

Recap • Components translated to native • Use Native components • Delay due to Bridge initialisation and runtime translation • Widget independent of the OS • No translation time needed • Include its own widgets

Slide 56

Slide 56 text

Fast Development Expressive and Flexible UI Native Performance Flutter Features

Slide 57

Slide 57 text

Common Interesting Features: • Hot reload without losing state

Slide 58

Slide 58 text

• Hot reload without losing state • Build on top of Hot Module Replacement by Webpack • HMR runtime included in the app that receives new module and replace it

Slide 59

Slide 59 text

• Hot reload without losing state • State is maintained during builds • Thanks to a mix of Ahead- of-time (AOT) and Just-In- Time (JIT) compilation

Slide 60

Slide 60 text

Common Interesting Features: • Hot reload without losing state • Update only components/widget that have changed

Slide 61

Slide 61 text

• Update only components/widget that have changed • Virtual DOM as representation of the UI OK! { type: 'button', props: { className: 'button button-blue', children: { type: 'b', props: { children: 'OK!' } } } }

Slide 62

Slide 62 text

• Update only components/widget that have changed • Virtual DOM as representation of the UI • Diff comparison using reconciliation • O(n) heuristic algorithm thanks to two assumption: • Two elements of different types will produce different trees. • The developer can hint at which child elements may be stable across different renders with a key prop.

Slide 63

Slide 63 text

• Update only components/widget that have changed • Element Tree as representation of the UI

Slide 64

Slide 64 text

• Update only components/widget that have changed • Element Tree as representation of the UI • After an user input or other stimuli a widget must be redrawn • Not a tree-diffing algorithm • For each element, the child list is examined independently 
 (O(n) algorithm)

Slide 65

Slide 65 text

Common Interesting Features: • Hot reload without losing state • Update only components/widget that have changed • “Frankestein” App

Slide 66

Slide 66 text

• “Frankestein” App • Add new React Native based features, screens, views, etc. in an existing application • Useful for “evolving features” • A view in the native app is a container for the RN component

Slide 67

Slide 67 text

• “Frankestein” App

Slide 68

Slide 68 text

• “Frankestein” App

Slide 69

Slide 69 text

EXAMPLE

Slide 70

Slide 70 text

render() { return ( ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, }, icon: { marginEnd: 10, padding: 20 }, });

Slide 71

Slide 71 text

render() { return ( ( { ... this.setState({ ... }) }} /> : {

Slide 72

Slide 72 text

render() { return ( ( { ... this.setState({ ... }) }} /> : {

Slide 73

Slide 73 text

barStyle="light-content" /> ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} />

Slide 74

Slide 74 text

data={this.state.items} renderItem={(item, index) => ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label}

Slide 75

Slide 75 text

/> ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, } });

Slide 76

Slide 76 text

data={this.state.items} renderItem={(item, index) => ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label}

Slide 77

Slide 77 text

renderItem={(item, index) => ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, }, icon: { marginEnd: 10, padding: 20 }, });

Slide 78

Slide 78 text

title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state}

Slide 79

Slide 79 text

render() { return ( ( { ... this.setState({ ... }) }} /> : { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, }, icon: { marginEnd: 10, padding: 20 }, });

Slide 80

Slide 80 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }

Slide 81

Slide 81 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name),

Slide 82

Slide 82 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name),

Slide 83

Slide 83 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name),

Slide 84

Slide 84 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name),

Slide 85

Slide 85 text

Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row(

Slide 86

Slide 86 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... ( ... ... >

Slide 87

Slide 87 text

body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() {

Slide 88

Slide 88 text

horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); },

Slide 89

Slide 89 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }

Slide 90

Slide 90 text

mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length,

Slide 91

Slide 91 text

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter vs React - Flutter Example"), ), body: Container( child: ListView.builder( itemBuilder: (BuildContext context, int index) { return Material( child: Container( margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5.0), padding: const EdgeInsets.symmetric( horizontal: 15.0, vertical: 10.0), decoration: new BoxDecoration( color: Colors.grey.shade300.withOpacity(0.3), borderRadius: new BorderRadius.circular(5.0), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }

Slide 92

Slide 92 text

Source Code bit.ly/react-native-sample bit.ly/flutter-sample bit.ly/flutter-better-sample

Slide 93

Slide 93 text

CONCLUSIONS

Slide 94

Slide 94 text

Crossplatform • Crossplatform is not bad but… IS NOT better than native • It’s a choice with compromises based on specific situation • If trouble became higher than benefits, make a step back

Slide 95

Slide 95 text

React Native or Flutter ? • Right now, React Native is more stable and solid • Flutter is the future • If Google does not drop it $ • Better performance that other framework • Dart is a more modern language

Slide 96

Slide 96 text

Flutter for Web • Rendering using standards-based web technologies: HTML, CSS and JavaScript https://flutter.dev/web

Slide 97

Slide 97 text

Desktop support https://flutter.dev/desktop

Slide 98

Slide 98 text

THANK YOU! twitter.com/marcoGomier github.com/prof18 marco.gomiero.93[at]gmail[dot]com marcogomiero.com

Slide 99

Slide 99 text

Bibliography / Useful Links • https://flutter.dev/docs/development/ui/widgets-intro • https://flutter.dev/docs/get-started/flutter-for/react-native-devs • https://facebook.github.io/react-native/docs/components-and-apis.html • https://levelup.gitconnected.com/wait-what-happens-when-my-react-native-application-starts-an-in-depth-look-inside-react-native-5f306ef3250f • https://flutter.dev/docs/resources/faq • https://flutter.dev/docs/resources/technical-overview • https://speakerdeck.com/mkonicek/under-the-hood-of-react-native • https://speakerdeck.com/frantic/react-native-under-the-hood • https://www.youtube.com/watch?v=rReCzR6DMEM • https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading • https://flutter.dev/docs/development/tools/hot-reload • https://reactjs.org/blog/2015/12/18/react-components-elements-and-instances.html • https://reactjs.org/docs/reconciliation.html • https://flutter.dev/docs/resources/inside-flutter • https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps • https://facebook.github.io/react-native/docs/integration-with-existing-apps • https://medium.com/snapp-mobile/multi-vs-cross-platform-in-the-age-of-flutter-6e76920028b6 • https://medium.com/dartlang/announcing-dart-2-80ba01f43b6 • https://medium.com/airbnb-engineering/sunsetting-react-native-1868ba28e30a • https://medium.com/flutter-io/hummingbird-building-flutter-for-the-web-e687c2a023a8