React Native or Flutter: Which should I choose? (Part three)

This is the last of a three-part series. In part one, we defined where React Native and Flutter fit in with all cross-platform solutions and why we’d want to focus on these two heavyweights. In part two, we compared their histories, design, and performance. And in part three (this part), we’ll look at the same component built in both React Native and in Flutter.


Code samples

The theory and the ideas are very important but many developers need to actually see some code before their minds are made up. After all, if the experience of development is miserable, your apps will be neither fast nor pretty because talented developers will choose to work with another framework — with you or with your competition. In order for you to get a complete picture we’ve developed an app that does exactly the same thing on both frameworks.

This demonstration app could be used by a movie theater to allow their users to reserve tickets for a show. They’ll choose a date and a movie to watch. They’ll choose a showtime and pick the seats they’ll sit in. The screenshot of the left is from the React Native version and the one on the right was created using Flutter. As you can see they are nearly identical.

The same application built in React Native (left) and Flutter (right). They are indistinguishable (except for a couple of small details I missed like centering and formatting).

This demo app involves the major capabilities you’d want to see exercised; custom components/widgets, stateless and stateful components/widgets, platform-specific coding, reading and writing to a database via a RESTful API, asynchronous coding and more. The entire codebase is available to you at https://github.com/rapPayne/react-native-vs-flutter. We’ve included some samples below and annotated them with notes. We’ll use these to compare as we dig deeper into the similarities and differences. Let’s start with the structure of a component.


Component structure

Remember that everything you write is a component in React Native or a widget in Flutter. Looking at this fundamental building block exposes major differences between the frameworks.

A stateful component in React Native

A stateful widget in Flutter

Notes:

1. The framework itself must be imported. React Native requires you to import each native component individually while Flutter imports them all as a group.

2. Since React Native uses JavaScript, the import of the Redux store is simpler. Flutter’s Dart makes creating a Redux store more complex.

3. Importing other custom components/widgets.

4. Creating a stateful class in React Native is much simpler than the equivalent in Flutter. Flutter explicitly splits its component into a state class and a component class. This is harder to write and learn but gives us more control.

5. The class’s constructor is called only on creation of the component.

6. Working with Redux. React Native allows more explicit control of state than Flutter. Both require you to call this.setState() in order to mutate state. This cannot be a coincidence. Google clearly learned some lessons from React Native’s successes. This is just another example of those lessons.

7. React Native has lifecycle methods that allow tight control over when things happen. Flutter has lifecycle methods also but because Flutter has separated a State class from the component class, Flutter needs fewer.

8. Where the visual component sub-tree is created. It must be a method called render() in React Native and must be called build() in Flutter. We’ll look at those methods in the next section.


Rendering components

Both frameworks have a required method of the class where the tree of sub-components are rendered. It is called render() in React Native and build() in Flutter. Here is the render() method of the Landing component made with React Native.

Building the UI in React Native

Building the UI in Flutter

Notes:

9. JavaScript’s huge user community has pushed it to include nifty capabilities like object destructuring. Dart still has to do things like this with fewer shortcuts. So in the Dart code we chose to leave these variables as store.state.*. Because JavaScript is dynamic and looser, the code can be much simpler. Note the use of StoreProvider and StoreConnector to connect to flutter_redux. These make the Redux wireups simpler but still more complex than the JavaScript versions.

10. A component/widget that allows full-screen viewing even on devices with a notch, like on the iPhone X. This is needed to wrap the Landing widget on Flutter so it is actually one level higher. It is called a SafeArea widget.

11. Allows the user to scroll contents by swiping their finger up and down. To overflow the screen in React Native creates an inaccessible area. This is bad. To overflow it it in Flutter is a runtime error. This is worse.

12. To layout components above and below in React Native, you wrap them in a plain <View> component. To lay them out side-by-side, you also use a <View> component, but you style it using flexbox like in HTML. In Flutter, above-and-below is done with Column widgets and side-by-side is done with Row widgets. This is more intuitive.

13. An image whose source is bundled with the application and deployed as part of the installation on each user’s device.

14. React Native makes it possible to set styles separately from components. Flutter requires that styling information resides in the individual widgets. This means styling at a lower level in Flutter but may make it easier to debug styling issues since the styling information will always be found in the same place.

15. A simple text component/widget.

16. The DatePicker is a custom component/widget. Because React Native uses the underlying platform-specific implementation for picking dates, it required us to use device detection (ie. “if iOS, do one thing. If Android, do another”). Flutter has the ability to match native look but never forces you to do that. So Flutter was much simpler.

17. This is conditional rendering. It is saying “if showings exist and a film has been selected, show the ShowingTimes custom component/widget”. Note that the React Native version uses JavaScript’s “truthiness” checking which is easier to write and read than the Dart/Flutter version. But the Dart/Flutter version is Typesafe and therefore more robust and debuggable. Note that neither framework allows an explicit if-else statement.

18. This is iterating; looping through a collection of objects and rendering one custom component/widget per member. Here, we are iterating the films and rendering one FilmBrief component/widget to draw the film’s poster, title, and tagline. Like before, neither framework allows the expected for loop but instead uses the .map() method.

19. Creating a modal window. Note that the structure is defined inside of it. This could be done inline or via a function call.


So which is better?

As you can see above, there are arguments for both. React Native has a declarative way of expressing the UI, whereas Flutter’s is imperative. React Native is more concise, but it also jumps between contexts — JSX and JavaScript — whereas Flutter stays consistent in Dart. React Native is dynamic and therefore quicker to develop but Flutter is strongly typed, thus safer.

Developers have opinions (duh). If you’re deciding between the two frameworks, you might want to run these snippets by your team and encourage a discussion as to which they feel would be more effective.

And don’t forget about part one of this series which gives a high-level overview of the two frameworks and part two which compares them directly in more detail.