SUBSCRIBE NOW
avatar
I always learn something just by skimming it that makes me want to bookmark the issue now and dig deeper later
SUBSCRIBE NOW
avatar
Keep up the good work with the newsletter 💪 I really enjoy it
SUBSCRIBE NOW
avatar
Dispatch is a must read for Android devs today and my go-to for keeping up with all things Jetpack Compose
SUBSCRIBE NOW
avatar
Dispatch has been my go-to resource as it's packed with useful information while being fun at the same time
SUBSCRIBE NOW
avatar
The content is light, fun, and still useful. I especially appreciate the small tips that are in each issue
SUBSCRIBE NOW
avatar
I truly love this newsletter ❤️‍🔥 Spot on content and I know there's a lot of effort that goes behind it
SUBSCRIBE NOW
avatar
Thanks for taking the time and energy to do it so well
JetpackCompose.app's Newsletter
avatar
I always learn something just by skimming it that makes me want to bookmark the issue now and dig deeper later
JetpackCompose.app's Newsletter
avatar
Keep up the good work with the newsletter 💪 I really enjoy it
JetpackCompose.app's Newsletter
avatar
Dispatch is a must read for Android devs today and my go-to for keeping up with all things Jetpack Compose
JetpackCompose.app's Newsletter
avatar
Dispatch has been my go-to resource as it's packed with useful information while being fun at the same time
JetpackCompose.app's Newsletter
avatar
The content is light, fun, and still useful. I especially appreciate the small tips that are in each issue
JetpackCompose.app's Newsletter
avatar
I truly love this newsletter ❤️‍🔥 Spot on content and I know there's a lot of effort that goes behind it
JetpackCompose.app's Newsletter
avatar
Thanks for taking the time and energy to do it so well

Compare Declarative Frameworks

Choose up-to 3 frameworks and learn how they compare to each other.
Framework Logo
Framework Logo
Framework Logo
Framework Logo
Framework Logo
Creating a new Component
Components are the reusable building blocks of your application. They are the most basic UI elements and can be used to build more complex components.
Jetpack Compose
kotlin
@Composable
fun MyComponent(
    displayString: String
) {
    Text(displayString)
}
React
jsx
function MyComponent(props) {
  return <div>{props.displayString}</div>;
}
Flutter
dart
class MyComponent extends StatelessWidget {
  final String displayString;

  MyComponent({required this.displayString});

  
  Widget build(BuildContext context) {
    return Text(displayString);
  }
}
Conditional Rendering
Conditional rendering is a technique used to display different UI components or content based on certain conditions, such as the value of a variable or the outcome of a boolean expression.
Jetpack Compose
kotlin
@Composable
fun ConditionalComponent(condition: Boolean) {
    if (condition) {
        Text("Condition is true")
    } else {
        Text("Condition is false")
    }
}

// Usage
ConditionalComponent(condition = true)
React
jsx
function ConditionalComponent({ condition }) {
  return (
    <>
      {condition ? (
        <p>Condition is true</p>
      ) : (
        <p>Condition is false</p>
      )}
    </>
  );
}

// Usage
<ConditionalComponent condition={true} />;
Flutter
dart
class ConditionalComponent extends StatelessWidget {
  final bool condition;

  ConditionalComponent({required this.condition});

  
  Widget build(BuildContext context) {
    if(condition) {
      return Text("Condition is true");
    } else {
      return Text("Condition is false");
    }
  }
}

// Usage
ConditionalComponent(condition: true)
Prop/Parameter Drilling
Prop/Parameter drilling is a technique where data is passed through multiple layers of components in the component hierarchy, often from a parent component to a deeply nested child component, via props or parameters.
Jetpack Compose
kotlin
@Composable
fun Parent(data: String) {
    IntermediateComponent(data = data)
}

@Composable
fun IntermediateComponent(data: String) {
    ChildComponent(data = data)
}

@Composable
fun ChildComponent(data: String) {
    Text("Received data: $data")
}

// Usage
Parent(data = "Some data")
React
jsx
function Parent({ data }) {
  return <IntermediateComponent data={data} />;
}

function IntermediateComponent({ data }) {
  return <ChildComponent data={data} />;
}

function ChildComponent({ data }) {
  return <p>Received data: {data}</p>;
}

// Usage
<Parent data="Some data" />;
Flutter
dart
class Parent extends StatelessWidget {
  final String data;

  Parent({required this.data});

  
  Widget build(BuildContext context) {
    return IntermediateComponent(data: data);
  }
}

class IntermediateComponent extends StatelessWidget {
  final String data;

  IntermediateComponent({required this.data});

  
  Widget build(BuildContext context) {
    return ChildComponent(data: data);
  }
}

class ChildComponent extends StatelessWidget {
  final String data;

  ChildComponent({required this.data});

  
  Widget build(BuildContext context) {
    return Text("Received data: $data");
  }
}

// Usage
Parent(data: "Some data")
Responding to events
Responding to events involves handling user interactions, such as button clicks or text input changes, and updating the component's state or triggering side effects accordingly.
Jetpack Compose
kotlin
@Composable
fun ClickableComponent() {
    var clicked by remember { mutableStateOf(false) }

    Button(onClick = { clicked = true }) {
        Text(if (clicked) "Button clicked" else "Click me")
    }
}
React
jsx
import { useState } from "react";

function ClickableComponent() {
  const [clicked, setClicked] = useState(false);

  return (
    <button onClick={() => setClicked(true)}>
      {clicked ? "Button clicked" : "Click me"}
    </button>
  );
}
Flutter
dart
class ClickableComponent extends StatefulWidget {
  
  _ClickableComponentState createState() => _ClickableComponentState();
}

class _ClickableComponentState extends State<ClickableComponent> {
  bool clicked = false;

  
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () => setState(() => clicked = true),
      child: Text(clicked ? "Button clicked" : "Click me"),
    );
  }
}
Handing user input
Handling user input involves capturing and processing user interactions with input fields, such as text fields, sliders, or checkboxes, and updating the component's state or triggering side effects based on the input.
Jetpack Compose
kotlin
@Composable
fun TextInputComponent() {
    var text by remember { mutableStateOf("") }

    TextField(
        value = text,
        onValueChange = { newText -> text = newText },
        label = { Text("Enter text") }
    )
}
React
jsx
function TextInputComponent() {
  const [text, setText] = useState("");

  return (
    <input
      type="text"
      value={text}
      onChange={(e) => setText(e.target.value)}
      placeholder="Enter text"
    />
  );
}
Flutter
dart
class TextInputComponent extends StatefulWidget {
  const TextInputComponent({super.key});

  
  State<TextInputComponent> createState() => _TextInputComponentState();
}

class _TextInputComponentState extends State<TextInputComponent> {
  late final _controller = TextEditingController(text: "");

  
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  
  Widget build(BuildContext context) {
    return TextField(
      controller: _controller,
      decoration: const InputDecoration(labelText: "Enter text"),
    );
  }
}
Previewing a Component
Creating a preview of a component involves displaying a visual representation of the component in the development environment to help with the design and layout process.
Jetpack Compose
kotlin
@Composable
fun ExampleComponent() {
    Text("Hello, World!")
}

@Preview(showBackground = true)
@Composable
fun ExampleComponentPreview() {
    ExampleComponent()
}

Additionally, you can also use Showkase, an open source library by Airbnb that allows you to view themes preview functions in an auto-generated component browser that can be viewed on an Android device.

React

React doesn't have a built-in preview feature. However, you can use a tool like Storybook to create previews for your components in a separate development environment.

Flutter

Flutter doesn't have a built-in preview feature. You can, however, create a separate app or run your app in an emulator or on a device to view your components. Additionally, you can use the Flutter Studio web-based tool to create and preview Flutter widgets in a browser.

Lists & Looping
Lists and looping involve rendering a dynamic number of components based on the length of a list or array, iterating over the list, and generating a UI component for each item.
Jetpack Compose
kotlin
@Composable
fun ListComponent(items: List<String>) {
    LazyColumn {
        items(items) { item ->
            Text(item)
        }
    }
}

// Usage
val items = listOf("Item 1", "Item 2", "Item 3")
ListComponent(items = items)
React
jsx
function ListComponent({ items }) {
  return (
    <ul>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  );
}

// Usage
const items = ["Item 1", "Item 2", "Item 3"];
<ListComponent items={items} />;
Flutter
dart
class ListComponent extends StatelessWidget {
  final List<String> items;

  ListComponent({required this.items});

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return ListTile(title: Text(items[index]));
      },
    );
  }
}

// Usage
final items = ["Item 1", "Item 2", "Item 3"];
ListComponent(items: items)
List item keys
List Item Keys are unique identifiers assigned to each list item in declarative UI frameworks to help manage and update list elements efficiently. Using List Item Keys enables the framework to optimize the rendering process, minimizing unnecessary updates and improving overall performance.
Jetpack Compose
kotlin
data class Person(val name: String, val age: Int, val id: String)

@Composable
fun ItemKeysExample(items: List<Person>) {
    LazyColumn {
        items(items, key = { person -> person.id }) { person ->
            Text("Name: ${person.name}, Age: ${person.age}")
        }
    }
}
React
jsx
function ItemKeysExample({ items }) {
  return (
    <ul>
      {items.map((person) => (
        <li key={person.id}>
          Name: {person.name}, Age: {person.age}
        </li>
      ))}
    </ul>
  );
}

// Usage
<ItemKeysExample
  items={[
    { name: "John", age: 30, id: "1" },
    { name: "Jane", age: 28, id: "2" },
    { name: "Bob", age: 25, id: "3" },
  ]}
/>;
Flutter
dart
class Person {
  final String name;
  final int age;
  final String id;

  Person({required this.name, required this.age, required this.id});
}

class ItemKeysExample extends StatelessWidget {
  final List<Person> items;

  ItemKeysExample({required this.items});

  
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        final person = items[index];
        return ListTile(
          key: Key(person.id),
          title: Text('Name: ${person.name}, Age: ${person.age}'),
        );
      },
    );
  }
}

// Usage
ItemKeysExample(items: [Person(name: 'John', age: 30, id: '1'), Person(name: 'Jane', age: 28, id: '2'), Person(name: 'Bob', age: 25, id: '3')])
Slot APIs
Slot APIs refer to a technique where components have customizable parts or 'slots' that can be filled with content when the component is being used. This allows for greater reusability and flexibility in composing user interfaces. The content that fills these slots can be other components or simple UI elements like text or images.
Jetpack Compose
kotlin
@Composable
fun Parent(
    header: @Composable () -> Unit,
    content: @Composable () -> Unit
) {
    Column {
        header()
        content()
    }
}

// Usage
Parent(
    header = { Text("Header") },
    content = { Child() }
)

@Composable
fun Child() {
    Text("Child Content")
}
React
jsx
function Parent({ header, content }) {
  return (
    <div>
      {header}
      {content}
    </div>
  );
}

// Usage
<Parent header={<h1>Header</h1>} content={<Child />} />;

function Child() {
  return <p>Child Content</p>;
}
Flutter
dart
class Parent extends StatelessWidget {
  final Widget header;
  final Widget content;

  Parent({required this.header, required this.content});

  
  Widget build(BuildContext context) {
    return Column(
      children: [
        header,
        content,
      ],
    );
  }
}

// Usage
Parent(
  header: Text("Header"),
  content: Child(),
)

class Child extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Text("Child Content");
  }
}
Modifiers
Modifiers are used to adjust or configure the UI elements' appearance or behavior in a declarative UI framework.
Jetpack Compose
kotlin
@Composable
fun ModifiersExample() {
    Text(
        "Hello, World!",
        modifier = Modifier
            .padding(16.dp)
            .background(Color.Blue)
    )
}
React

React doesn't have a direct analog to modifiers in Jetpack Compose or SwiftUI. Instead, you can use inline styles or CSS classes.

jsx
function ModifiersExample() {
  const style = {
    padding: "16px",
    backgroundColor: "blue",
    color: "white",
  };

  return <div style={style}>Hello, World!</div>;
}
Flutter

In Flutter, you can wrap widgets with other widgets to achieve similar effects.

dart
class ModifiersExample extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(16.0),
      color: Colors.blue,
      child: Text('Hello, World!', style: TextStyle(color: Colors.white)),
    );
  }
}
State
State management refers to the process of handling and updating the internal state of components, often in response to user interactions or other events.
Jetpack Compose
kotlin
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count = count + 1 }) {
        Text("Count: $count")
    }
}
React
jsx
import { useState } from "react";

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

  return (
    <button onClick={() => setCount(count + 1)}>
        Count: {count}
    </button>
  );
}
Flutter
dart
class Counter extends StatefulWidget {
  
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int count = 0;

  
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: () => setState(() => count += 1),
      child: Text("Count: $count"),
    );
  }
}
Scoped Data Propagation
Scoped Data Propagation is a technique that involves passing data across multiple levels of a component subtree without having to explicitly pass it through every intermediate component. It helps reduce the complexity of prop drilling and allows for a more efficient way of sharing data in a specific scope.
Jetpack Compose
kotlin
val CustomLocal = compositionLocalOf<String> { "Default data" }

@Composable
fun Parent(data: String) {
    CompositionLocalProvider(CustomLocal provides data) {
        Intermediate()
    }
}

@Composable
fun Intermediate() {
    Child()
}

@Composable
fun Child() {
    val data = CustomLocal.current
    Text("Received data: $data")
}

// Usage
Parent(data = "Some data")
React
jsx
import { createContext, useContext } from "react";

const CustomContext = createContext();

function Parent({ data }) {
  return (
    <CustomContext.Provider value={data}>
      <Intermediate />
    </CustomContext.Provider>
  );
}

function Intermediate() {
  return <Child />;
}

function Child() {
  const data = useContext(CustomContext);
  return <p>Received data: {data}</p>;
}

// Usage
<Parent data="Some data" />;
Flutter
dart
class CustomInheritedWidget extends InheritedWidget {
  final String data;

  CustomInheritedWidget({required this.data, required Widget child})
      : super(child: child);

  
  bool updateShouldNotify(CustomInheritedWidget oldWidget) {
    return oldWidget.data != data;
  }

  static CustomInheritedWidget of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CustomInheritedWidget>()!;
  }
}

class Parent extends StatelessWidget {
  final String data;

  Parent({required this.data});

  
  Widget build(BuildContext context) {
    return CustomInheritedWidget(
      data: data,
      child: Intermediate(),
    );
  }
}

class Intermediate extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Child();
  }
}

class Child extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final data = CustomInheritedWidget.of(context).data;
    return Text("Received data: $data");
  }
}

// Usage
Parent(data: "Some data")
Side Effects
A side effect involves executing code that can have external consequences or perform operations that are not directly related to rendering the UI, such as making network requests or updating external data sources.
Jetpack Compose
kotlin
@Composable
fun SideEffectOnLoadComponent() {
    LaunchedEffect(Unit) {
        // Perform side effect, e.g. fetch data, update external data source
    }

    // Other UI components
    Text("Hello, World!")
}
React
jsx
import { useEffect } from "react";

function SideEffectOnLoadComponent() {
  useEffect(() => {
    // Perform side effect, e.g. fetch data, update external data source
  }, []);

  // Other UI components
  return <div />;
}
Flutter
dart
class SideEffectOnLoadComponent extends StatefulWidget {
  
  _SideEffectOnLoadComponentState createState() => _SideEffectOnLoadComponentState();
}

class _SideEffectOnLoadComponentState extends State<SideEffectOnLoadComponent> {
  
  void initState() {
    super.initState();
    // Perform side effect, e.g. fetch data, update external data source
  }

  
  Widget build(BuildContext context) {
    // Other UI components
    return Container();
  }
}