Implement Manager init() and Commands correctly
mainIn the Pragmatic Flutter Architecture (PFA), distinguish between data loading and UI interaction:
init(): Used for loading initial data via direct API calls. Do not use commands insideinit().- Commands: The UI-facing reactive interface. Widgets watch
isRunning,errors, andresults.
Crucial Rule: Do not nest commands. If a command needs to refresh data after a mutation (e.g., after a delete), call the API directly inside the command body instead of calling another command's .run() method.
class MyManager {
final items = ValueNotifier<List<Item>>([]);
// Command for UI-triggered refresh (widget watches isRunning)
late final loadCommand = Command.createAsyncNoParam<List<Item>>(
() async {
final result = await di<ApiClient>().getItems();
items.value = result;
return result;
},
initialValue: [],
);
// init() calls API directly — no command needed
Future<MyManager> init() async {
items.value = await di<ApiClient>().getItems();
return this;
}
}
// ✅ Direct API call inside command
late final deleteCommand = Command.createAsync<int, bool>((id) async {
final result = await di<ApiClient>().delete(id);
items.value = await di<ApiClient>().getItems(); // reload directly
return result;
}, initialValue: false);
// ❌ Don't call another command from inside a command
late final deleteCommand = Command.createAsync<int, bool>((id) async {
final result = await di<ApiClient>().delete(id);
loadCommand.run(); // WRONG — nesting commands
return result;
}, initialValue: false);