Skip to content

Declarative UI

The most reassuring thing about Flutter for React developers is that the declarative UI model is identical at its core: your UI is a pure function of state. When state changes, you describe the new UI and the framework figures out what to update. The difference is in the plumbing — Flutter has its own element tree and reconciler instead of the virtual DOM, but the mental model you already have is exactly right.

UI = f(state): same idea, different plumbing

Section titled “UI = f(state): same idea, different plumbing”
React
// React — declarative counter
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(c => c + 1)}>
Increment
</button>
</div>
);
}
Flutter
// Flutter — declarative counter (StatefulWidget)
class Counter extends StatefulWidget {
const Counter({super.key});
@override
State<Counter> createState() => _CounterState();
}
class _CounterState extends State<Counter> {
int _count = 0;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Text('Count: $_count',
style: const TextStyle(fontSize: 24)),
ElevatedButton(
onPressed: () => setState(() => _count++),
child: const Text('Increment'),
),
],
);
}
}
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Counter(),
        ),
      ),
    );
  }
}

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

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

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'Count: $_count',
          style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
        ),
        const SizedBox(height: 16),
        ElevatedButton(
          onPressed: () => setState(() => _count++),
          child: const Text('Increment', style: TextStyle(fontSize: 18)),
        ),
        const SizedBox(height: 8),
        OutlinedButton(
          onPressed: () => setState(() => _count = 0),
          child: const Text('Reset'),
        ),
      ],
    );
  }
}
Which statement about Flutter's declarative model is true?
What Flutter method is the equivalent of React's setState?
What is Flutter's equivalent of the React virtual DOM?
In Flutter, when does the build() method run?