sudolabs logo

13. 7. 2020

3 min read

Flutter and React Native performance overview

I've been playing with Flutter for a bit again, and this time I tried to come up with a simple example of how its performance compares to ReactNative. (Tested on IOS, iPhone SE2) I built a card list app with rudimentary UI and 300 items in length. I used both ReactNative and Flutter for comparison and then analyzed the performance.

Jozef Petro

performance tables

and which one is better for your product?

I've been playing with Flutter for a bit again, and this time I tried to come up with a simple example of how its performance compares to ReactNative. (Tested on IOS, iPhone SE2) I built a card list app with a rudimentary UI and 300 items in length. I used both ReactNative and Flutter for comparison and then analyzed the performance.

The app's layout is side by side.

layouts

Analyzing performance

The metric that I picked for the analysis is FPS in time (Frames per second).

I tried to perform a similar set of actions accurately in both apps:

  • Waiting for the first picture

  • Start scrolling as fast as I could

  • Change scroll direction three times

  • Performed in 30 seconds timeline

Time spent on the app can also be useful from a dev performance perspective. In my case, it's a bit biased because I have much more experience with ReactNative and Javascript, while on the other hand, this was the first list I built in Flutter.

The time spent including project setup:

  • ReactNative around 45 minutes

  • Flutter around 1.5 hour

For the scrolling components, I used:

  • FlatList in case of ReactNative

  • ListView in case of Flutter

When I started analyzing the performance, first, I can look at the app FPS on startup and when the app becomes actually usable:

  • For ReactNative - 2 seconds in and we're still on 1 FPS

  • For Flutter - 2 seconds in and we're good to go at 39 FPS

Performance profiling result.

perfomance tables

You can feel the difference between the two.

When I started scrolling, I pretty much didn't have any significant problems. Flutter seemed smoother, and it can also be seen when you compare the charts and how ReactNative's FPS is more unstable. It's worth noting that once I picked up the scroll speed on React Native, I started to see how items are mounted, which caused a bit of flickering (really tiny, but noticeable).

Here you can see how FPS is much more unstable in ReacNative. The Y axis shows range from 0 - 60 FPS.

performance charts

From the implementation perspective

ReactNative wins the game for me, because it's just so friendly for developers experienced in Javascript (me).

Code for the ReactNative implementation.

import React from 'react';
import {
SafeAreaView,
StyleSheet,
View,
Text,
ImageBackground,
FlatList,
StatusBar,
} from 'react-native';
const LIST_DATA = new Array(300).fill('');
const CARD_RADIUS = 8;
const Card = () => (
<View style={styles.cardWrapper}>
<View style={styles.cardImageWrapper}>
<ImageBackground
source={{uri: 'https://picsum.photos/150'}}
style={styles.cardImage}
/>
</View>
<View style={styles.cardTextWrapper}>
<Text>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry. Lorem Ipsum has been the industry's standard.
</Text>
</View>
</View>
);
const App = () => {
return (
<>
<StatusBar barStyle="dark-content" />
<SafeAreaView>
<FlatList
data={LIST_DATA}
renderItem={() => <Card />}
keyExtractor={(_, index) => index.toString()}
/>
</SafeAreaView>
</>
);
};
const styles = StyleSheet.create({
cardWrapper: {
height: 150,
margin: 10,
flexDirection: 'row',
alignItems: 'center',
borderRadius: CARD_RADIUS,
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 5,
},
shadowOpacity: 0.36,
shadowRadius: 6.68,
elevation: 11,
backgroundColor: '#fff',
},
cardImageWrapper: {
flex: 1,
overflow: 'hidden',
borderTopLeftRadius: CARD_RADIUS,
borderBottomLeftRadius: CARD_RADIUS,
},
cardImage: {
flex: 1,
resizeMode: 'cover',
justifyContent: 'center',
height: 150,
},
cardTextWrapper: {
flex: 1,
paddingLeft: 10,
flexDirection: 'row',
justifyContent: 'flex-start',
},
});
export default App;

When they write in Flutter docs that everything is a widget, they mean it. It has extensive API to learn. Even if it tries to mitigate HTML / CSS layouting approaches and the way of decorating elements, there's a class for everything, even for basic styling of borders and shadows. So you need to get at least an overview, and this takes time.

Code of the Flutter implementation for comparison.

import 'package:flutter/material.dart';
import 'dart:ui' as ui;
void main() {
runApp(
MediaQuery(
data: MediaQueryData.fromWindow(ui.window),
child: Directionality(
textDirection: TextDirection.ltr,
child: SafeArea(
child: CardList(),
),
),
),
);
}
const double CARD_RADIUS = 8;
class Card extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(CARD_RADIUS)),
boxShadow: [
BoxShadow(
color: Colors.grey,
blurRadius: 10,
spreadRadius: 1,
)
],
),
margin: EdgeInsets.all(10),
height: 150,
child: Row(
children: <Widget>[
Expanded(
child: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(CARD_RADIUS),
bottomLeft: Radius.circular(CARD_RADIUS)),
child: Image(
image: NetworkImage('https://picsum.photos/150'),
height: 150,
fit: BoxFit.cover,
),
),
),
Expanded(
child: Container(
padding: EdgeInsets.only(left: 10),
child: Text(
"Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard.",
style: TextStyle(color: Colors.black),
),
),
),
],
),
);
}
}
class CardList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(color: Colors.white),
child: ListView.separated(
itemBuilder: (BuildContext context, int index) {
return Card();
},
separatorBuilder: (BuildContext context, int index) =>
const Divider(height: 3, color: Colors.transparent),
itemCount: 300),
);
}
}

Why am I trying it then?

I see massive potential in implementing more advanced concepts where the tooling and utils for everything can help significantly. Advanced routing, animations, real native feeling, and better performance - these factors contribute to a better product experience and more options. I think it's just a trade-off, which makes sense to me.

Share

Let's start a partnership together.

Let's talk

Our basecamp

700 N San Vicente Blvd, Los Angeles, CA 90069

Follow us


© 2023 Sudolabs

Privacy policy
Footer Logo

We use cookies to optimize your website experience. Do you consent to these cookies and processing of personal data ?