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. Flutter or React Native a cross-platform dilemma Marco Gomiero

  2. WHO I AM Mobile Engineer @ Uniwhere MARCO GOMIERO COMPUTER

    ENGINEER Co-Leader @ GDG Venezia
  3. LET’S GET IN TOUCH! twitter.com/marcoGomier MARCO GOMIERO COMPUTER ENGINEER github.com/prof18

    marco.gomiero.93[at]gmail[dot]com marcogomiero.com
  4. Disclaimer

  5. Background

  6. Background Flutter React Native

  7. Background Flutter

  8. Background Flutter

  9. Background Flutter

  10. Background Flutter

  11. Background Flutter

  12. Background Flutter

  13. Background Flutter

  14. Agenda • History • Language • UI • Under the

    hood • Example • Conclusions
  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
  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
  17. Trends React Native Flutter UPDATE Last update: September 2019

  18. Trends Last update: September 2019

  19. LANGUAGE

  20. Survey

  21. React Native • Javascript • ☠ for Object Oriented Devs:

    • Type Conversion • Sometimes silently fails • Prototype based inheritance • Ecosystem Confusion
  22. None
  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
  24. !crusade It’s not a language crusade, just my experience

  25. UI

  26. None
  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" } });
  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, ), ), ); }
  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, ), ), ); }
  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" } });
  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" } });
  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" } });
  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" } });
  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”
  35. https://facebook.github.io/react-native/docs/components-and-apis.html

  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, ), ), ); }
  37. // Flutter import 'package:flutter/material.dart'; void main() { runApp( Center( child:

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

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

    Text( 'Hello, world!', textDirection: TextDirection.ltr, ), ), ); }
  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
  41. Structural Element (Button, Menu …)

  42. Stylistic Element (Font, Color Scheme ..)

  43. Aspect of Layout (Padding, Align ..)

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

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

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

    to JSX • Flutter: remains in the Dart context • Possibility of UI modularisation
  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, ..
  48. 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/
  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
  50. None
  51. Jetpack Compose https://developer.android.com/jetpack/compose

  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!") }
  53. None
  54. https://developer.apple.com/xcode/swiftui/

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

  56. UNDER THE HOOD

  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
  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
  59. • Calls passed between JS to Native in a “batched

    asynchronous way” • quequed in the MessageQueue -> flushed every 5 ms by default • Event driven
  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
  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
  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
  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
  64. Common Interesting Features: • Hot reload without losing state

  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
  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
  67. Common Interesting Features: • Hot reload without losing state •

    Update only components/widget that have changed
  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!' } } } }
  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.
  70. • Update only components/widget that have changed • Element Tree

    as representation of the UI
  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)
  72. Common Interesting Features: • Hot reload without losing state •

    Update only components/widget that have changed • “Frankestein” App
  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
  74. • “Frankestein” App

  75. • “Frankestein” App

  76. EXAMPLE

  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 }, });
  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={() => {
  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={() => {
  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} />
  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}
  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, } });
  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}
  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 }, });
  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}
  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 }, });
  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, ), ), ); }
  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),
  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),
  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),
  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),
  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(
  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>
  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(() {
  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(() { ... }); }), ], ), ), ); },
  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, ), ), ); }
  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,
  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, ), ), ); }
  99. Source Code bit.ly/react-native-sample bit.ly/flutter-sample bit.ly/flutter-better-sample

  100. CONCLUSIONS

  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
  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
  103. Flutter for Web • Rendering using standards-based web technologies: HTML,

    CSS and JavaScript https://flutter.dev/web
  104. Desktop support https://flutter.dev/desktop

  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
  106. THANK YOU! twitter.com/marcoGomier github.com/prof18 marco.gomiero.93[at]gmail[dot]com marcogomiero.com