Flutter: First Impressions
We will quickly run through an explanation of these parts, what they are and how they compare to React Native, before wrapping up with some first impressions of the technology and its viablitity as a cross-platform option.
In future posts we’ll dive a bit deeper into specific topics like native-interop and asynchronous programming in Flutter.
🖌 Runtime and Renderer
The Flutter runtime, like React Native, is written in C++ and hosts the Dart virtual machine. It interfaces with the underlying native platform and provides rendering, as well as common functionality like networking, I/O, file access etc.
Flutter uses Skia, an open-source rendering library, to draw all of its widgets onto a single app canvas. Skia is the rendering engine that powers popular web-browsers like Google Chrome and Mozilla Firefox. React Native, on the other hand, uses the native drawing capabilities of the platform to render its components. There are trade-offs to both approaches.
The advantage to Flutter’s approach is that you can be confident that widgets will render almost identically on both platforms. This means less tweaking of view styles and less
Platform.OS === "android" ? /* hack */ : /* normal */ like code.
The downside is that you lose some of the look and feel of the native platform components. This is fine if your app has a highly branded look, but overall your apps will feel more Android than iOS.
Another downside is that it is difficult to integrate components that render natively (e.g. a map view). Luckily, the Flutter team have recently implemented the
PlatformView to alleviate this.
Flutter gives you direct access to the drawing API, so you can even use it to make more general 2D programs, like games (see Flame).
From a distance Dart looks like Java. It has similar keywords, hanging curly braces and semi-colons. It will feel familiar, at least, to anyone with Java experience, which is almost everyone with an undergraduate degree in Computer Science.
One might be disappointed by Dart at first. Maybe you expected modern features found in languages like Swift and Kotlin, like optional/null type safety. Don’t despair, Dart may surprise you with its depth. For example, it has an Actor-based concurrency system similar to Erlang (see Isolates), it supports mixins, has generic type reification and code generators.
undefined is not a function errors.
Typescript or Flow do help mitigate this problem by providing better compile-time type-safety. Unfortunately, a lot of packages in the React Native are written in pure ES6 and a lot of problems do emerge at runtime.
📖 Platform SDK
// React Native (JSX) return ( <View> <Text></Text> <TouchableOpacity onPress=> <Text>Increment</Text> </TouchableOpacity> </View> ); // Flutter return Column( children: <Widget>[ Text('$_count'), IconButton(icon: Icon(Icons.add), onPressed: _incrementCount) ], );
It can be difficult to track the closing parentheses, so most IDEs (IntelliJ and VS Code) will insert a
// Widgetcomment after each closing bracket to simulate the closing tags you would find in JSX.
You might have picked that Flutter has distinct widgets for layout like
Fill etc. By comparison React Native allows you to set flex layout properties on most components via the
style property. In practice I have found that this slightly increases the depth of the render tree but also makes it clearer, at a glance, how the layout works.
In Flutter there is a distinction between stateful and stateless widgets. You can think of this as comparable to a convention in the React community for separating components into Presentational and Container. There have been in-roads made introducing the Redux pattern into Flutter as well, but at this point the debug tools and third-party middleware is not as mature.
The Flutter development experience feels leaner than React Native. You install the
flutter command line program and then run
flutter doctor to figure out anything you’re missing. This is a nice touch, because one of the nightmarish parts of cross-platform development is getting all of your dependencies installed and playing nicely.
In general, I found the
flutter command-line experience to be more intuitive and streamlined than the
react-nativeequivalent. Compile times and dependency download also seem faster. This is probably because React, and a lot of the other JS libraries, are large and require time to bundle together into a single JS blob.
Hot-reloading seems to actually work in Flutter and I haven’t once experienced my computer grinding to a halt when running the app for long periods. In supported IDEs (IntelliJ) you can use the stepping debugger to execute code line-by-line, drop and replay stack frames etc.
💥 Wrapping up
The outlook for Flutter looks good: it has strong tooling, more compile-time safety, a powerful runtime and rendering engine.
One area I haven’t looked at yet is how easy it is to interop with the underlying native platform. A cursory look at the documentation reveals a promising API and good language support (Swift and Kotlin). I haven’t looked into its limitations. For example, threading support, latency passing data back and forth across the native bridge etc.
Stay posted for more articles about Flutter and other cross-platform technologies. Sayonara! 👋