Setup and First Run¶
This page walks you through your first successful run of a Flutter application using SimpleAppState.
By the end of this page, you will have:
a working Flutter project
SimpleAppState added as a dependency
a running example that you can modify and experiment with
No prior knowledge of SimpleAppState is required.
Prerequisites¶
You need a working Flutter development environment.
If Flutter is not yet installed, follow the official guide:
Flutter SDK installation: https://docs.flutter.dev/get-started/install
You can use any supported IDE:
Android Studio: https://developer.android.com/studio
VS Code: https://code.visualstudio.com/
After installation, verify the setup from the console.
flutter doctor
Make sure there are no blocking issues before continuing.
Create a new Flutter project¶
First, create a new Flutter project:
flutter create simple_app_state_demo
cd simple_app_state_demo
Run the default counter app once to confirm everything works:
flutter run
You should see Flutter’s standard counter example running. This confirms that your environment is set up correctly.
Add SimpleAppState¶
Open the simple_app_state_demo project you just created in your IDE.
Open pubspec.yaml and add SimpleAppState to your dependencies:
dependencies:
flutter:
sdk: flutter
simple_app_state: any
Then fetch the dependencies:
flutter pub get
If you’re using Android Studio, you can also do this by clicking Pub get near the top right.
Replace lib/main.dart¶
Next, replace the contents of lib/main.dart with the following complete example.
This single file contains:
application state definition
Flutter setup
UI code
Copy and paste the code exactly as shown.
Complete example¶
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:simple_app_state/simple_app_state.dart';
///////////////////////////////////////////////////////////////////////////////
///
/// Application State Definition (This is usually written in lib/ui/app_state.dart.)
///
/// - Widgets do NOT own application state.
/// - StateSlots are defined once and reused everywhere.
///
///////////////////////////////////////////////////////////////////////////////
/// A state container shared across the app
final appState = SimpleAppState();
/// counter value(`int`)
final countSlot = appState.slot<int>('count', initial: 0);
/// log(`List<String>`)
final logsSlot = appState.slot<List<String>>(
'logs',
initial: [],
caster: (raw) => (raw as List).cast<String>(),
);
void main() {
/// You can easily define a debugger to use only during development.
if (kDebugMode) {
appState.setDebugListener((slot, oldV, newV) {
/// You can also use slot.name here to print only in a specific slot.
debugPrint(
"Changed Slot:${slot.name}, Value changed from:$oldV, to:$newV",
);
});
}
runApp(const MyApp());
}
///////////////////////////////////////////////////////////////////////////////
///
/// Flutter Application
///
///////////////////////////////////////////////////////////////////////////////
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: CounterPage());
}
}
///////////////////////////////////////////////////////////////////////////////
///
/// UI Layer
///
/// Widgets subscribe to StateSlots.
/// They never store application state themselves.
///
///////////////////////////////////////////////////////////////////////////////
class CounterPage extends SlotStatefulWidget {
const CounterPage({super.key});
@override
List<StateSlot> get slots => [countSlot, logsSlot];
@override
SlotState<CounterPage> createState() => _CounterPageState();
}
class _CounterPageState extends SlotState<CounterPage> {
@override
Widget build(BuildContext context) {
final count = countSlot.get();
final logs = logsSlot.get();
return Scaffold(
appBar: AppBar(title: const Text('SimpleAppState Example')),
body: Column(
children: [
const SizedBox(height: 32),
Text(
'Count: $count',
style: Theme.of(context).textTheme.headlineMedium,
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
appState.batch(() {
countSlot.update((v) => v + 1);
logsSlot.update((oldCopy) {
oldCopy.add('Increment at ${DateTime.now()}');
return oldCopy;
});
});
},
child: const Text('Increment (batched)'),
),
const Divider(height: 32),
Expanded(
child: ListView.builder(
itemCount: logs.length,
itemBuilder: (context, index) {
return ListTile(title: Text(logs[index]));
},
),
),
],
),
);
}
}
Run the application¶
Save the file and run the app again:
flutter run
Tap the Increment button. You should see the counter value update immediately.
Congratulations — you are now running a Flutter app powered by SimpleAppState 🎉
What just happened?¶
Even in this small example, several important ideas are visible:
application state is defined outside widgets
widgets subscribe to state explicitly
state updates are performed via update
UI rebuilds are deterministic and predictable
Do not worry if all details are not clear yet. The next pages explain these ideas step by step.
Next step¶
Now that you have a working example, let’s look at how this code is typically organized in real projects.
Go to Understanding the Basics section.