Flutter and React Native are cross-platform frameworks that were developed by two tech giants as technologies to power apps of the future. Flutter is young compared to the more mature React Native, but both are still new on the market and have every chance of becoming the most widely used framework. I decided to create a small and simple project in both Flutter and React Native and share my impressions with you.

I’m an Android developer, but I also have expertise in cross-platform development with React Native. When I heard about Flutter, I was excited to try it, as Flutter is closer to native Android development while React Native is more familiar to web developers.

I created two similar projects: one in React Native and the other in Flutter. I wanted to compare these two frameworks, find out which is more convenient for me, and explore differences between Flutter and React Native and their similarities.

First, I’ll give you a quick overview of Flutter and React Native, discuss their pros and cons, and tell you what you need to know before choosing between them. Then we’ll look at my examples. At the end of this article I’ll tell you what I liked about each framework and what difficulties I encountered.

React Native vs Flutter

React Native and Flutter have lots of prospects in the mobile development market, as they’re both high-quality cross-platform frameworks developed by experienced companies: Facebook and Google, respectively.

React Native was presented in 2015, two years earlier than Flutter. This leads to some advantages for React Native.

First of all, it’s the community. Currently, the React Native community is twice as big as the Flutter community. Because of this, there are significantly more frameworks and libraries for React Native. If your app has a bit more than just basic functionality, chances are that in Flutter you’ll need to develop some things from scratch.

That said, I believe that this year the number of libraries and tools for Flutter will grow and equal the number for React Native.

For the time being, I’d prefer working with React Native for this reason alone. I think, however, that Flutter is a great technology to learn now, as it has Google’s support, great documentation, and lots of far-reaching plans. Flutter is slated to become the main language of Google’s new operating system called Fuchsia.

Flutter is extremely convenient to work with, and I’ll repeat that once again when I show you my examples. If you want to learn more about what’s great about Flutter and React Native, as well as compare their drawbacks, check out the article I wrote in which I compare these two technologies from a more theoretical point of view.

Now let’s get to my app examples. I’ll show you how I implemented a simple app with just three screens:

  • splash screen with a timer
  • home screen
  • navigation screen

I’ll show you code samples and tell you what I learned in the process.

How to implement a simple app: React Native and Flutter comparison

Splash screen – Flutter

flutter splash screen
This is how a Flutter splash screen looks on Android and iOS

First, I created a component for a splash screen: a full-fledged screen with a simple layout and a simple image with the Mobindustry logo that loads from the app’s resources.

In this piece of code, Void main initializes the main method for this screen: runApp. runApp launches the whole application. The main method is stored in the main.dart file, and I also added home and routes to it, as you can see below.

void main() {
  runApp(new MaterialApp(
    home: new SplashScreen(),
    routes: <String, WidgetBuilder>{
      '/HomeScreen': (BuildContext context) => new HomeScreen(),
      '/DartIsAwesome': (BuildContext context) => new DartIsAwesome()
    },
  ));
}

Next I described the splash screen:

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => new _SplashScreenState();
}

class _SplashScreenState extends State {

I implemented a four-second timer to create a redirect from the splash screen to the home page:

 startTimer() async {
    var _duration = new Duration(seconds: 4);
    return new Timer(_duration, navigationPage);
  }

  void navigationPage() {
    Navigator.of(context).pushReplacementNamed('/HomeScreen');
  }

This is how the timer is initialized:

  @override
  void initState() {
    super.initState();
    startTimer();
  }

This piece of code creates a view with an image. I set a white background and set the image to be in the center of the screen:

 @override
  Widget build(BuildContext context) {
    return new Scaffold(
        backgroundColor: Colors.white,
        body: new Center(
        child: new Image.asset('images/logo.png'),
      ),
    );
  }
}

Splash screen – React Native

react native splash screens
Splash screens on Android and iOS, implemented with React Native

The AppJS file is set for app navigation with a default splash screen:

export default class App extends React.Component {
  render() {
    return 
  }
}

Here I created a StackNavigator where I configured the navigation settings and toolbar styles.

const AppNavigator = createStackNavigator({
  splash: { screen: Splash,
     navigationOptions: { header: null }
          },
  home: { screen: Home,
     navigationOptions: {
      title: "Example app",
      headerLeft: null,
      headerStyle: {
      backgroundColor: '#42A5F5',
   },headerTitleStyle: {
      color: '#fff'
    }
    } },
    details: { screen: Details,
      navigationOptions: {
       title: "Example app",
       headerTintColor: 'white',
       headerStyle: {
       backgroundColor: '#42A5F5',
    },headerTitleStyle: {
       color: '#fff'
     }
     }   },
    initialRouteName: 'splash',
});

Home screen – Flutter

flutter homescreen
Flutter Homescreen on Android and iOS

Here’s an example of implementing a Flutter home screen. I really liked the code I ended up with, as I created a customizable class for each section and it made the code function really well while keeping it short.

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => new _HomeScreenState();
}

class _HomeScreenState extends State {
  @override
  Widget build(BuildContext context) {
    // Declare some constants
    final double myTextSize = 30.0;
    final double myIconSize = 40.0;
    final TextStyle myTextStyle =
    new TextStyle(color: Colors.grey, fontSize: myTextSize);

    var column = new Column(
      // Makes the cards stretch in horizontal axis
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        // Setup the card
        new MyCard(
          // Setup the text
            title: new Text(
              "Favorite",
              style: myTextStyle,
            ),
            // Setup the icon
            icon:
            new Icon(Icons.favorite, size: myIconSize, color: Colors.red)),
        new MyCard(
            title: new Text(
              "Alarm",
              style: myTextStyle,
            ),
            icon: new Icon(Icons.alarm, size: myIconSize, color: Colors.blue)),
        new MyCard(
            title: new Text(
              "Airport Shuttle",
              style: myTextStyle,
            ),
            icon: new Icon(Icons.airport_shuttle,
                size: myIconSize, color: Colors.amber)),
        new MyCard(
            title: new Text(
              "Done",
              style: myTextStyle,
            ),
            icon: new Icon(Icons.done, size: myIconSize, color: Colors.green)),
      ],
    );

    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Example App"),
      ),
      body: new Container(
        // Sets the padding in the main container
        padding: const EdgeInsets.only(bottom: 2.0),
        child: new Center(
          child: new SingleChildScrollView(child: column),
        ),
      ),
    );
    ;
  }

}


This is the card class, which you can configure without any problems:

class MyCard extends StatelessWidget {
  final Widget icon;
  final Widget title;

  // Constructor. {} here denote that they are optional values, i.e you can use as: new MyCard()
  MyCard({this.title, this.icon});

This code is responsible for view rendering. A GestureDetector is used to determine the gestures. I set it to react to taps and redirect to the DartIsAwesome screen.

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: (){
        Navigator.of(context).pushNamed('/DartIsAwesome');
      },
        child: new Container(
          padding: const EdgeInsets.only(bottom: 1.0),
          child: new Card(
            child: new Container(
              padding: const EdgeInsets.all(20.0),
              child: new Column(
                children: [this.title, this.icon],
              ),
            ),
          ),
        )
    );
  }
}

Details screen – React Native

With this piece of code, I created a constructor and initialized the parameters:

export default class App extends React.Component {

  constructor(props){
       super(props)
       this.state = {
         count: 0,
         myArray : ["Mobindustry!", "React Native", "is", "cool", "and", "awesome!"]
       }
       this.incrementCount = this.incrementCount.bind(this)
   }


Then I created code that processes taps on the button:

  incrementCount() {
   if (this.state.count < this.state.myArray.leght-1) {
     this.setState({ count: this.state.count + 1 })
   } 
  }

To make the View render on-screen, I used this code:

 render() {
    return (
      
        {this.state.myArray[this.state.count]}
        
      
    );
  }
}
// var myArray = ["React Native", "is", "cool", "and", "awesome!"];

These are styles I used for the details screen. As you can see, the logic is very similar to JavaScript and CSS:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  image: {
    width :40,
    height:40,
    resizeMode: 'stretch',
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize : 26,
    marginBottom : 8,
    fontWeight : 'bold'
  },
  button: {
    width:70,
    color: '#B71C1C',
    fontSize : 16
  }
});

This is pretty much all the code I used to create a Flutter and React Native mobile application with three screens. I showed you the most interesting parts of the code so you can see the differences in implementation logic.

To find out how to implement a details screen in Flutter and a home screen in React Native, check out the Flutter and React Native documentation.

My conclusion

Dart, the language Flutter is based on, is much more pleasant to code in for an Android developer like me. The structure of this programming language is clear, and this is one of the biggest benefits of Flutter. But because Dart is young, it’s still challenging sometimes to create something more than the simplest and most basic things.

An experienced developer, however, will figure it out without any major problems. It took me only eight hours to do research, set up the development environment, and implement three screens. With React Native, it took me 20 hours – more than twice as long.

I was a bit stuck with React Native when it came to navigation libraries. There are a few libraries, and some of them are native. They’re very similar at first glance, and you need to pay attention and make sure you use a native library, as they work a bit better and have different logic.

My installed React Native app is 43.77 MB, and my Flutter app weighs 44.26 MB. The APK files of both these apps weigh around 17 MB, which is still too much. If I created them with native technologies, they’d weigh around 3 MB

One of the biggest benefits of React Native is its new set of tools called expo. Expo facilitates the whole installation process as well as launching the app, creating builds, and so on. It’s a really advanced and useful service that does everything for you.

One of the biggest advantages of Flutter is of course its working through Android Studio. You can use Flutter in Xcode as well, launch Flutter apps on iPhones, and so on. Flutter feels extremely native for any Android developer who has worked with Java or Kotlin. If compare React Native vs Flutter performance, Flutter is the leader here as well.

Both Flutter and React Native have a great feature called hot reload. It allows you to see all the changes in the application instantly.

One drawback that React Native and Flutter share is the size of the APK file and the installed app. React Native and Flutter apps are extremely big compared to native
apps.

You’ve seen the apps I created: they’re really simple and have only three screens. If I created them with native technologies, they’d weigh around 3 MB.

Instead, my installed React Native app is 43.77 MB, and my Flutter app weighs 44.26 MB. The APK files of both these apps weigh around 17 MB, which is still too much.

I should note, however, that if I continued on making the app more complex and adding more screens, the app size wouldn’t increase drastically. The majority of the app’s size comes from the software that launches the app.

The size of cross-platform apps leads to another restriction: they can’t support instant apps, as this feature works only for apps that are less than 10 MB in size.

I believe that soon this issue with app sizes will be resolved both in React Native and in Flutter. Both of these technologies are evolving at a great pace.

Timing still matters though, and React Native is currently still more advanced than Flutter. If Flutter and React Native were equally developed, I’d definitely choose Flutter. But because of a lack of libraries and APIs, I’d choose React Native, at least for the next three to four months. I hope this comparison between Flutter and React Native was useful for you. If you have any questions, don’t hesitate to contact Mobindustry.

Cross-platform development services

Want to create your project using the latest technologies? Seeking to save your budget with a cross-platform?

Get a Free Consultation!
Request Callback

Request Callback

+