DEV Community

Cover image for Uncovering the Parallels: Flutter and React Native
Louie John
Louie John

Posted on

Uncovering the Parallels: Flutter and React Native

X is better than Y ... Y is better than X... Yada Yada 🥱

Two heavyweight champs dominate the scene when it comes to cross-platform app development: Flutter and React Native. These titans often go toe-to-toe in developer debates, but I'm not here to crown a winner. Instead, let's uncover the similarities between these two powerful frameworks.

🔄 Hot Reload

A standout feature in both Flutter and React Native, offering developers a powerful tool to enhance their workflow efficiency. This feature allows developers to instantly see the results of their code changes without restarting the entire application.

Different mechanisms were done under the hood on how each of these frameworks handles Hot Reload, but one common component that they have is utilizing a Virtual Machine.

For more information check the official docs:
React Native Hot Reload
Flutter Hot Reload

💢 Declarative and Reactive UI

It's no secret that Flutter comes with a modern React-style framework. Flutter was inspired by React's approach to handling state changes in interfaces during runtime, unlike other imperative UI frameworks.

As we quote from their documentation:

This model is inspired by work that came from Facebook for their own React framework, which includes a rethinking of many traditional design principles.

Widgets 🟰🟰 Components

Both Flutter widgets and React Native components are reusable pieces of code that serve as the building blocks for our application's user interfaces.

🎯 Core Components
These are fundamental components that are ready to use within each framework.

  • Flutter - there are two sets of UI languages we can choose when it comes to Flutter components: Material Design and Cupertino Design.

    • Material Design - created by Google to be used in Android, iOS, Web, and Desktop apps.
    • Cupertino Design - created by Apple based on Apple's Human Interface Guidelines, which apply the current iOS design language.

With these two design languages, Flutter can choose from. Flutter can deliver consistent interfaces across both platforms using its rendering engine Skia. This means you can render Material Design components on iOS and vice versa. How you utilize this flexibility is entirely up to you.

In Flutter 3.10, Impeller replaces the Skia engine and becomes the primary rendering engine on iOS Impeller to solve the early-onset jank problem.

  • React Native - components are rendered using the native UI components from their respective interfaces. Check their official docs for available components.

Shopify engineers have introduced the option to use Skia in React Native. For more details, check out their official post.

✍🏻 Custom Components
As the name implies these are components tailored to specific functionalities. Both of these frameworks allows us to write reusable custom components to handle platform-specific functions, customize core components, third-party module integration, etc.

📱 Layouts

Another inspiration Flutter gets from web technology is the Flexbox layout model. But instead of configuring it through styling, Flutter layout's mechanism is through Widgets.

  • Flex and Expand

Handle filling available spaces along the main axis (Row or Column).

React Native CSS flex

 <View style={{flex: 1, flexDirection: 'column'}>
   <View style={{flex: 1, backgroundColor: 'red'}} />
   <View style={{flex: 2, backgroundColor: 'darkorange'}} />
   <View style={{flex: 3, backgroundColor: 'green'}} />
 </View>
Enter fullscreen mode Exit fullscreen mode

Flutter Widget Expand

Column(
  children: <Widget>[
    Expanded(
      flex: 1,
      child: Container(
        color: Colors.red,
      ),
    ),
    Expanded(
      flex: 2,
      child: Container(
        color: Colors.orange,
      ),
    ),
    Expanded(
      flex: 3,
      child: Container(
        color: Colors.green,
      ),
    ),
  ],
)
Enter fullscreen mode Exit fullscreen mode
  • Flex Direction

Specifies what direction the main axis is to lay out its children.

React Native CSS flexDirection

<View style={{flexDirection: 'row'}}>
     <Text>Deliver features faster</Text>
     <Text>Craft beautiful UIs</Text>
</View>
Enter fullscreen mode Exit fullscreen mode

Flutter Widget Row/Column.


// Horizontal position
const Row(
  children: [
    Text('Deliver features faster'),
    Text('Craft beautiful UIs')
  ],
)

// Vertical position
const Column(
  children: [
    Text('Deliver features faster'),
    Text('Craft beautiful UIs')
  ],
)
Enter fullscreen mode Exit fullscreen mode
  • Alignment

Determining the layout direction of a UI involves alignment, which specifies how the children of the UI are arranged along its axes:

Main axis is the primary axis along which flex items are laid out.

Cross axis is perpendicular to the main axis. It determines the alignment of items within the flex container perpendicular to the main axis.

Using the previous code sample of Flex Direction:

React Native CSS justifyContent and alignItems

<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-end'}}>
     <Text>Deliver features faster</Text>
     <Text>Craft beautiful UIs</Text>
</View>
Enter fullscreen mode Exit fullscreen mode

Flutter property mainAxisAlignment and crossAxisAlignment.

const Row(
   mainAxisAlignment: MainAxisAlignment.spaceBetween,
   crossAxisAlignment: CrossAxisAlignment.end,
  children: [
    Text('Deliver features faster'),
    Text('Craft beautiful UIs')
  ],
)
Enter fullscreen mode Exit fullscreen mode
  • Wrap Manages wrapping of multiple lines along the main axis to prevent child components from overflowing their parent.

React Native CSS flexWrap

<View style={styles.wrapContainer}>
    <View style={styles.item}><Text>Item 1</Text></View>
    <View style={styles.item}><Text>Item 2</Text></View>
    <View style={styles.item}><Text>Item 3</Text></View>
    <View style={styles.item}><Text>Item 4</Text></View>
    <View style={styles.item}><Text>Item 5</Text></View>
 </View>

const styles = StyleSheet.create({
  wrapContainer: {
    flexDirection: 'row',
    flexWrap: 'wrap', // Enable wrapping
    justifyContent: 'space-between', // Optional: Adjust spacing
    margin: 10,
  },
  item: {
    padding: 10,
    margin: 5,
    backgroundColor: 'lightblue',
  },
});
Enter fullscreen mode Exit fullscreen mode

Flutter Widget Wrap

Wrap(
  spacing: 10.0, // Gap between adjacent children
  runSpacing: 10.0, // Gap between lines
  children: [
    Container(
      padding: EdgeInsets.all(8),
      color: Colors.red,
      child: Text('Item 1'),
    ),
    Container(
      padding: EdgeInsets.all(8),
      color: Colors.blue,
      child: Text('Item 2'),
    ),
    Container(
      padding: EdgeInsets.all(8),
      color: Colors.green,
      child: Text('Item 3'),
    ),
    Container(
      padding: EdgeInsets.all(8),
      color: Colors.yellow,
      child: Text('Item 4'),
    ),
    Container(
      padding: EdgeInsets.all(8),
      color: Colors.orange,
      child: Text('Item 5'),
    ),
  ],
)
Enter fullscreen mode Exit fullscreen mode

Conclusion

The main point is that rather than arguing over which framework is superior, we should focus on learning common concepts and patterns that are transferable between them. I enjoy working with both technologies and would be glad to use either to solve a problem.

Top comments (0)