Flutter setState()
The simplest way to manage state in Flutter
🔄 What is setState()?
setState() is Flutter's built-in method for updating widget state. It tells Flutter to rebuild the widget when data changes, making your UI reactive and dynamic for simple state management needs.
// Simple counter example
setState(() {
counter++;
});
Key Concepts
Simple
Easy to learn and use
setState(() {
value = newValue;
});
Reactive
UI updates automatically
// Changes trigger rebuild
_counter++;
Built-in
No external packages needed
// Part of StatefulWidget
class MyWidget extends StatefulWidget
Local State
Perfect for widget-level data
// State stays in widget
bool _isVisible = true;
🔹 Basic Counter Example
The classic Flutter counter using setState():
import 'package:flutter/material.dart';
class CounterApp extends StatefulWidget {
@override
_CounterAppState createState() => _CounterAppState();
}
class _CounterAppState extends State<CounterApp> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Text(
'$_counter',
style: TextStyle(fontSize: 48),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
child: Icon(Icons.add),
),
);
}
}
Output:
A counter app that displays a number and increments it when the floating button is pressed.
🔹 Toggle Visibility Example
Show and hide widgets using setState():
class ToggleWidget extends StatefulWidget {
@override
_ToggleWidgetState createState() => _ToggleWidgetState();
}
class _ToggleWidgetState extends State<ToggleWidget> {
bool _isVisible = true;
void _toggleVisibility() {
setState(() {
_isVisible = !_isVisible;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
if (_isVisible)
Container(
padding: EdgeInsets.all(20),
color: Colors.blue,
child: Text('Hello Flutter!'),
),
ElevatedButton(
onPressed: _toggleVisibility,
child: Text(_isVisible ? 'Hide' : 'Show'),
),
],
);
}
}
Output:
A button that toggles the visibility of a blue container with text.
🔹 Form Input Example
Handle user input with setState():
class NameForm extends StatefulWidget {
@override
_NameFormState createState() => _NameFormState();
}
class _NameFormState extends State<NameForm> {
String _name = '';
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
onChanged: (value) {
setState(() {
_name = value;
});
},
decoration: InputDecoration(
labelText: 'Enter your name',
),
),
SizedBox(height: 20),
Text(
'Hello, $_name!',
style: TextStyle(fontSize: 24),
),
],
);
}
}
Output:
A text field that displays a greeting with the entered name in real-time.
🔹 When to Use setState()
✅ Good For:
- Simple widget-level state
- Form inputs and validation
- Toggle switches and checkboxes
- Animations and UI changes
- Small apps with minimal state
❌ Not Ideal For:
- Sharing state between many widgets
- Complex app-wide state
- State that needs to persist
- Large-scale applications
🔹 Common Mistakes
Avoid these common setState() pitfalls:
// ❌ Wrong: Modifying state without setState
void _increment() {
_counter++; // UI won't update!
}
// ✅ Correct: Use setState
void _increment() {
setState(() {
_counter++;
});
}
// ❌ Wrong: Async operations in setState
setState(() async {
await fetchData(); // Don't do this!
});
// ✅ Correct: Async before setState
void _loadData() async {
final data = await fetchData();
setState(() {
_data = data;
});
}