How Jetpack Compose, React, and SwiftUI Are Converging — A New Era of Declarative UI Development

Sumeet Panchal
5 min readSep 27, 2024

--

Declarative UI Approach — The promising UI construct

UI frameworks have evolved significantly over the years, and today we are witnessing a convergence around declarative UI programming. Modern frameworks like Jetpack Compose (Android), React (Web/React Native), and SwiftUI (iOS/macOS) are making UI development more predictable and easier by introducing state-driven UIs that update automatically. This shared direction simplifies the transition for front-end developers across platforms with minimal learning effort.

In this blog, we will explore how Jetpack Compose, React, and SwiftUI converge in their UI development approach and how developers can leverage these similarities to become versatile across platforms.

Understanding Declarative UI Programming

The shift from imperative to declarative programming in UI development is at the heart of this convergence. In imperative programming, you explicitly describe every step the UI must follow to change in response to events. However, in declarative programming, you can tell what the UI should look like at any given point, and the framework efficiently handles the rest.

- Declarative UI: Jetpack Compose vs. React vs. SwiftUI

Let’s take a quick look at how UI elements are declared in these frameworks.

  • React (JavaScript):
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
  • Jetpack Compose (Kotlin):
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}
  • SwiftUI (Swift):
struct Greeting: View {
var name: String

var body: some View {
Text("Hello, \(name)!")
}
}

In each case, the UI is declared based on state (in this case, the name), and the framework automatically re-renders (or recomposes) the UI when the state changes.

- State Management and Recomposition

At the core of declarative UIs is state management. In all three frameworks, changes to the state trigger updates (recomposition or re-rendering) of the corresponding UI elements.

React: In React, the state is typically managed using the useState hook and any change to the state triggers a re-render of the affected components.

function Counter() {
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}

useState defines the state and the setter (setCount).

  • When setCount is called, React automatically re-renders the UI to reflect the new state.

Jetpack Compose: In Jetpack Compose, you use remember and mutableStateOf to manage the state, and changes to the state trigger recomposition.

@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }

Column {
Text("You clicked $count times")
Button(onClick = { count++ }) {
Text("Click me")
}
}
}

remember and mutableStateOf work together to define the reactive state.

  • When the state changes (count++), the relevant part of the UI is recomposed automatically.

SwiftUI: In SwiftUI, @State is used to declare a mutable state, and any change to this state causes the view to re-render.

struct Counter: View {
@State private var count = 0

var body: some View {
VStack {
Text("You clicked \(count) times")
Button("Click me") {
count += 1
}
}
}
}

@State defines a piece of state that SwiftUI monitors for changes.

  • When the count is incremented, SwiftUI automatically re-renders the view.

Key Insight: Despite slight differences in syntax, all three frameworks follow the same pattern of binding state to the UI and automatically updating (recomposing or rendering) when the state changes. This similarity drastically reduces the learning curve for transitioning between frameworks.

- Component-Based Architecture

All three frameworks use a component-based approach, where each UI element is treated as a reusable, self-contained component (or view/composable).

React: In React, UI elements are broken into components, which can be nested and reused across the app.

function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}

function App() {
return (
<div>
<Greeting name="Alice" />
<Greeting name="Bob" />
</div>
);
}

Jetpack Compose: Jetpack Compose calls these reusable components composables.

@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name!")
}

@Composable
fun App() {
Column {
Greeting(name = "Alice")
Greeting(name = "Bob")
}
}

SwiftUI: In SwiftUI, reusable UI elements are called views.

struct Greeting: View {
var name: String

var body: some View {
Text("Hello, \(name)!")
}
}

struct App: View {
var body: some View {
VStack {
Greeting(name: "Alice")
Greeting(name: "Bob")
}
}
}s

Key Insight: In each framework, UI is broken down into small, manageable pieces that can be reused across the app. This component-based architecture makes it easy to manage complex UIs and facilitates transitions between the frameworks, as the concepts remain consistent.

- Handling Side Effects and Lifecycle Events

Side effects, such as network requests or setting up event listeners, must be handled carefully to avoid performance issues. Each framework has a specific way of dealing with these.

React: React uses the useEffect hook for managing side effects. It runs after every render (or when specific dependencies change).

useEffect(() => {
// Side effect: Fetching data
fetchData();

return () => {
// Cleanup effect
cleanup();
};
}, []);

Jetpack Compose: Jetpack Compose handles side effects with LaunchedEffect, which runs a block of code in a coroutine when a key changes or during the first composition.

@Composable
fun SideEffectExample() {
LaunchedEffect(Unit) {
// Side effect: Fetching data
fetchData()
}
}

SwiftUI: In SwiftUI, onAppear and onDisappear are used to manage side effects tied to view appearance and disappearance.

struct ContentView: View {
var body: some View {
Text("Hello, world!")
.onAppear {
// Side effect: Fetching data
fetchData()
}
.onDisappear {
// Cleanup effect
cleanup()
}
}
}

Key Insight: Though the syntax varies, side effect management is conceptually similar across these frameworks. This makes it easier for developers familiar with side effects in one framework to adapt to another.

- Cross-Platform Transition: Why It’s Easier Now

The striking similarities between Jetpack Compose, React, and SwiftUI make transitioning between them surprisingly easy.

For example, a React developer already familiar with hooks (useState, useEffect) can easily understand Jetpack Compose’s remember and LaunchedEffect, or SwiftUI’s @State and onAppear. Likewise, an Android developer proficient in Jetpack Compose can transition into SwiftUI by simply learning the syntax, as the core concepts of state management, recomposition, and component-based UIs remain the same.

Why this matters:

• The convergence of these frameworks means you don’t need to start from scratch when moving from one to another.

• As long as you understand state-driven UIs and component-based architecture, you can become proficient in another framework with minimal effort.

  • This drastically reduces the learning curve, enabling you to contribute to cross-platform projects and become more versatile as a front-end developer.

- Conclusion: Embrace the Convergence of UI Frameworks

Modern UI frameworks like Jetpack Compose, React, and SwiftUI are converging around common principles of declarative UIs, state management, and componentization. This convergence is great news for front-end developers because it allows you to expand your skillset across platforms without having to re-learn the fundamentals. Whether you’re a web developer transitioning to mobile, or an Android developer learning iOS, the similarities across these frameworks make the process smooth and efficient.

Ready to cross platforms? Start exploring these frameworks by applying the principles you already know, and you’ll be surprised how much you already understand!

https://medium.com/@sumeetpanchal-21/choosing-the-right-mobile-app-development-framework-in-2024-a-clear-guide-for-long-term-success-ec99fdaeb7a5

Happy coding!

--

--

Sumeet Panchal
Sumeet Panchal

Written by Sumeet Panchal

Programming enthusiast specializing in Android and React Native, passionate about crafting intuitive mobile experiences and exploring innovative solutions.

No responses yet