Flutter or React Native, a cross-platform dilemma | DevFest Veneto 19

Flutter or React Native, a cross-platform dilemma | DevFest Veneto 19

Nowadays the hype around Flutter is raising a lot. But what about the “(not so) old-fashioned” React Native? In this talk, we will see the basics and the differences between the two frameworks. In particular, we will understand how to build User Interfaces and how the internals of the two framework works. Finally, we will try to understand when and why to choose a cross-platform framework and which of the two. All this journey is based on the true story of an Android Developer that he wanted to explore the cross-platform jungle both for work and fun reasons.

9da5d5cc4b6a9f28058152e28364b02a?s=128

Marco Gomiero

November 16, 2019
Tweet

Transcript

  1. 14.

    Agenda • History • Language • UI • Under the

    hood • Example • Conclusions
  2. 15.

    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
  3. 16.

    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
  4. 19.
  5. 20.
  6. 21.

    React Native • Javascript • ☠ for Object Oriented Devs:

    • Type Conversion • Sometimes silently fails • Prototype based inheritance • Ecosystem Confusion
  7. 22.
  8. 23.

    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
  9. 25.

    UI

  10. 26.
  11. 27.

    // React Native import React from "react"; import { StyleSheet,

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

    // React Native import React from "react"; import { StyleSheet,

    Text, View } from "react-native"; export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text>Hello world!</Text> </View> ); } } 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, ), ), ); }
  13. 29.

    // React Native import React from "react"; import { StyleSheet,

    Text, View } from "react-native"; export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text>Hello world!</Text> </View> ); } } 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, ), ), ); }
  14. 30.

    // React Native import React from "react"; import { StyleSheet,

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

    // React Native import React from "react"; import { StyleSheet,

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

    // React Native import React from "react"; import { StyleSheet,

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

    // React Native import React from "react"; import { StyleSheet,

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

    // React Native import React from "react"; import { StyleSheet,

    Text, View } from "react-native"; export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text>Hello world!</Text> </View> ); } } 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”
  19. 36.

    // React Native import React from "react"; import { StyleSheet,

    Text, View } from "react-native"; export default class App extends React.Component { render() { return ( <View style={styles.container}> <Text>Hello world!</Text> </View> ); } } 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, ), ), ); }
  20. 37.

    // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child:

    Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
  21. 38.

    // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child:

    Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
  22. 39.

    // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child:

    Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
  23. 40.

    // 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
  24. 45.

    Components vs Widgets: Summary • React Native: jumps from Javascript

    to JSX • Flutter: remains in the Dart context • Possibility of UI modularisation
  25. 46.

    Components vs Widgets: Summary • React Native: jumps from Javascript

    to JSX • Flutter: remains in the Dart context • Possibility of UI modularisation
  26. 47.

    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, ..
  27. 49.

    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
  28. 50.
  29. 52.

    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!") }
  30. 53.
  31. 57.

    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
  32. 58.

    • 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
  33. 59.

    • Calls passed between JS to Native in a “batched

    asynchronous way” • quequed in the MessageQueue -> flushed every 5 ms by default • Event driven
  34. 60.

    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
  35. 61.

    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
  36. 62.

    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
  37. 63.

    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
  38. 65.

    • 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
  39. 66.

    • 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
  40. 67.

    Common Interesting Features: • Hot reload without losing state •

    Update only components/widget that have changed
  41. 68.

    • Update only components/widget that have changed • Virtual DOM

    as representation of the UI <button class='button button-blue'> <b> OK! </b> </button> { type: 'button', props: { className: 'button button-blue', children: { type: 'b', props: { children: 'OK!' } } } }
  42. 69.

    • 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.
  43. 71.

    • 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)
  44. 72.

    Common Interesting Features: • Hot reload without losing state •

    Update only components/widget that have changed • “Frankestein” App
  45. 73.

    • “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
  46. 76.
  47. 77.

    render() { return ( <View > <StatusBar backgroundColor="#1976D2" barStyle="light-content" />

    <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> </View> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, }, icon: { marginEnd: 10, padding: 20 }, });
  48. 78.

    render() { return ( <View > <StatusBar backgroundColor="#1976D2" barStyle="light-content" />

    <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => {
  49. 79.

    render() { return ( <View > <StatusBar backgroundColor="#1976D2" barStyle="light-content" />

    <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => {
  50. 80.

    barStyle="light-content" /> <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label}

    containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} />
  51. 81.

    data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId ==

    index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label}
  52. 82.

    /> <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container}

    rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> </View> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, } });
  53. 83.

    data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId ==

    index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label}
  54. 84.

    renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index

    ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> </View> ); } 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 }, });
  55. 85.

    title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop"

    size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state}
  56. 86.

    render() { return ( <View > <StatusBar backgroundColor="#1976D2" barStyle="light-content" />

    <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem title={item.label} containerStyle={styles.container} rightIcon={this.state.playingId == index ? <Icon style={styles.icon} color="black" name="stop" size={20} onPress={() => { ... this.setState({ ... }) }} /> : <Icon style={styles.icon} color="black" name="play" size={20} onPress={() => { this.setState({ ... }) ... }} />} /> )} extraData={this.state} keyExtractor={item => item.label} /> </View> ); } const styles = StyleSheet.create({ container: { borderRadius: 5, backgroundColor: "#F3F3F3", marginHorizontal: 10, marginVertical: 5, }, icon: { marginEnd: 10, padding: 20 }, });
  57. 87.

    @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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }
  58. 88.

    @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: <Widget>[ Text(_items[index].name),
  59. 89.

    @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: <Widget>[ Text(_items[index].name),
  60. 90.

    @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: <Widget>[ Text(_items[index].name),
  61. 91.

    @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: <Widget>[ Text(_items[index].name),
  62. 92.

    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(
  63. 93.

    @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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... <FlatList data={this.state.items} renderItem={(item, index) => ( <ListItem> ... </ListItem> ... > </FlatList>
  64. 94.

    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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() {
  65. 95.

    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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); },
  66. 96.

    @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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }
  67. 97.

    mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new

    Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length,
  68. 98.

    @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: <Widget>[ Text(_items[index].name), IconButton( icon: _playing ? new Icon(Icons.stop) : new Icon(Icons.play_arrow), onPressed: () { ... setState(() { ... }); }), ], ), ), ); }, itemCount: _items.length, ), ), ); }
  69. 101.

    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
  70. 102.

    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
  71. 103.
  72. 105.

    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