command_hooks 0.0.2
command_hooks: ^0.0.2 copied to clipboard
A Flutter Hooks library providing Result-like async primitives, Commands for event handlers, and utilities for managing async operations.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:command_hooks/commands.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'command_hooks Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const CounterPage(),
);
}
}
/// Example page demonstrating [useCommand] hook.
///
/// This example shows how to use [useCommand] to handle async operations
/// in event handlers with automatic debouncing and state management.
class CounterPage extends HookWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
final counter = useState(0);
// useCommand creates a debounced async action
// Only one invocation can run at a time
final counterCmd = useCommand(() async {
// Simulate an API call
await Future.delayed(const Duration(seconds: 1));
counter.value++;
return counter.value;
}, []);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('command_hooks Example'),
actions: [
IconButton(
icon: const Icon(Icons.refresh),
onPressed: counterCmd.reset,
tooltip: 'Reset',
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('You have pushed the button this many times:'),
const SizedBox(height: 16),
// Use mapOrElse to handle all states
counterCmd.current.mapOrElse(
pending: () => const CircularProgressIndicator(),
err: (error) => Text(
'Error: $error',
style: Theme.of(context)
.textTheme
.headlineMedium
?.copyWith(color: Colors.red),
),
ok: (value) => Text(
'${value ?? counter.value}',
style: Theme.of(context).textTheme.headlineMedium,
),
) ?? Text(
'${counter.value}',
style: Theme.of(context).textTheme.headlineMedium,
),
],
),
),
floatingActionButton: FloatingActionButton(
// Disable button while command is loading (uses convenience getter)
onPressed: counterCmd.isLoading ? null : counterCmd.invoke,
tooltip: 'Increment',
child: counterCmd.isLoading
? const SizedBox(
width: 24,
height: 24,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Icon(Icons.add),
),
);
}
}