Starting with Flutter (from React Native)

At the end of 2018 / start of 2019, I wanted to fill in my knowledge of modern UI approaches. I have worked with native iOS and Android, and more recently, largely with React and React Native. The gaps I wanted to fill in were macOS (native), Electron, and Flutter, which I'll report on here.

Impressions

TL;DR: I was very impressed. Flutter feels like Google looked at React Native, liked the core ideas, but thought it was a massive series of hacks (it is, for better and worse!) and ordered a bunch of smart people to build something similar from scratch. (I think that is nearly true, except they actually repurposed their Dart programming language and Skia library for it.)

The documentation is great (such a contrast with doing macOS native development, which I was doing around the same time, where the documentation is awful).

It allows you to build fully reactive user interfaces, cleanly separating state and view. The hot reloading seems to be a lot more robust than React Native's version. Debugging view hierarchies and so on is great with first-class tooling built into IntelliJ (or Android Studio).

Code completion/editing is generally great, though I'm not a big fan of Dart. It is okay, but it doesn't really lend itself to functional programming. The lack of algebraic data types—along the lines of Kotlin's sealed classes, TypeScript's discriminated unions, or Swift's enums—is frustrating. Also, sometimes the compiler seems to miss things that you would expect it to catch. You often have to create many classes where, in other platforms/systems, a single function would suffice. Tuples would also be nice. Though if you are coming from Java, Dart will likely seem amazing! (But semicolons, why? Does the Dart team hate us? It was 2019!)

Flutter really likes Widgets, using them for many things that, e.g., React Native would use styles for. This can lead to extremely nested, verbose code. To be honest, I can't tell if this is that bad; it looks ugly, but so did JSX for the first few days. Some things are a bit annoying and lead to seemingly unnecessary code duplication: stateless widgets would be a function in React (Native), but in Flutter, they are a class, so you have to declare members, pass them into a constructor (albeit with a shorthand syntax), and then use them again in your build method. Stateful Widgets are worse: you actually create two classes for some reason that I don't entirely follow (explanations suggest this is required for reuse at runtime or is good for hot reloading). For styling, well, there isn't any: you can have themes and set various properties on widgets or via nesting widgets, but it doesn't have anything analogous to React Native's StyleSheets.

(De)serialization of JSON is way more work than in JavaScript/TypeScript (as you don't really have to do it there!). I used a code generator for this, and it was a bit of a pain. On the flip side, some of the related code would have been native in React Native, but in Flutter, it was just Dart (e.g., reading/writing a file).

Performance appears to be great, as promised. I tested on a five-year-old Android device that often struggles with native Android apps, and it worked well. If anything, some things seemed to be a bit smoother than on my iPhone X, but that may be because Android's animations are set up to disguise dropped frames near the start of a transition.

What I built: Modern Colour Picker

I generally don't think you can evaluate an approach until you ship something with it (even if you ship something small). I made and shipped Modern Colour Picker to both iOS and Android. The app uses Material Design and code generation for JSON persistence. The only native code is on iOS, where I wrote some custom code for sharing (on Android, I didn't have to).

Modern Colour Picker Screenshot

Modern Colour Picker Screenshot

Modern Colour Picker Screenshot

When should you choose Flutter and/or React Native

Maybe favour Flutter if:

  • You want to be able to create custom animations and graphics code
  • Performance is a concern, e.g., for older Android devices
  • You don't have a designer and are willing to use the (great) Material Design 2.0 implementation
  • You know Java already (Dart is like taking half a JavaScript-y step toward Kotlin from Java!)
  • You know Dart already (that seems unlikely)
  • Android is a priority (while React Native has improved here, it is definitely weaker; I found Flutter on Android to seemingly outperform regular Native Android)

Maybe favour React Native if:

  • You are working with a content-heavy JSON or GraphQL API
  • You have a custom look and feel you want to achieve (possibly from a dedicated designer)
  • You know React (and/or have a web version to support). Please don't try to make the same code run on both mobile and web; React is 'learn once, write everywhere' (but that is for another article)!
  • You know JavaScript/TypeScript. Please use TypeScript, though; it was 2019. You will thank me later.
  • iOS is a priority

Conclusion

In many areas, Flutter exceeds React Native. It is way more polished and straightforwardly performant. The tooling is great. So, switch? Maybe, but actually, for most apps, I think either will work great. Both do fully reactive UI, something which, outside the web, appears to be hard to find.

My conclusion from just a few days of Flutter is actually that native app development is probably moribund for most purposes: now that you can do straightforward cross-platform, highly custom animations, that addresses (let's make up numbers) 10% or whatever of use cases that React Native struggles with. Perhaps there is still a small percentage of use cases left (making something up, let's say, 5%) that need individual native implementations. Flutter and React Native are both at the point that they are often better choices for a single platform (due to reactive UI and fast iteration with hot/live reload), never mind that they can serve both major mobile platforms.

SwiftUI and Jetpack Compose might change this picture, but both were extremely early at the time of writing (and SwiftUI only supports iOS 13+, etc., so it wasn't going to be viable for many use cases for over two years).

Resources

I watched a few talks on YouTube; this Udemy Course is pretty good (I picked out 10% or so of it to watch), but mostly I just looked things up as needed from the official website, which is great.

Modern Colour Picker Screenshot