Uncovering the Parallels: Flutter and React Native
Tags: flutter, reactnative, learning, mobile
Published: 2024-07-13 22:42:17

## 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](https://reactnative.dev/blog/2016/03/24/introducing-hot-reloading)
> [Flutter Hot Reload](https://docs.flutter.dev/tools/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](https://www.youtube.com/watch?time_continue=2&v=x7cQ3mrcKaY&feature=emb_logo), 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](https://skia.org/about/). 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](https://docs.flutter.dev/perf/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](https://reactnative.dev/docs/components-and-apis) for available components.

> Shopify engineers have introduced the option to use Skia in React Native. For more details, check out their official [post](https://shopify.engineering/getting-started-with-react-native-skia).


✍🏻 **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`
```js
 <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>
```

Flutter Widget `Expand`
```dart
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,
      ),
    ),
  ],
)
```

- **Flex Direction**

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

React Native CSS `flexDirection`
```js
<View style={{flexDirection: 'row'}}>
     <Text>Deliver features faster</Text>
     <Text>Craft beautiful UIs</Text>
</View>
```

Flutter Widget `Row/Column`. 
```dart

// 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')
  ],
)
```
- **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`
```js
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-end'}}>
     <Text>Deliver features faster</Text>
     <Text>Craft beautiful UIs</Text>
</View>
```

Flutter property `mainAxisAlignment` and `crossAxisAlignment`. 
```dart
const Row(
   mainAxisAlignment: MainAxisAlignment.spaceBetween,
   crossAxisAlignment: CrossAxisAlignment.end,
  children: [
    Text('Deliver features faster'),
    Text('Craft beautiful UIs')
  ],
)
```
- **Wrap**
Manages wrapping of multiple lines along the main axis to prevent child components from overflowing their parent.


React Native CSS `flexWrap`
```js
<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',
  },
});
```
Flutter Widget `Wrap`
```dart
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'),
    ),
  ],
)
```

## 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.