flutter_dva_hooks 1.0.9
flutter_dva_hooks: ^1.0.9 copied to clipboard
Declarative hooks for Flutter Dva state management. Provides useDvaConnect, useDvaProps, and useDvaStore hooks on flutter_hooks for reactive store access in Flutter widgets.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_dva/flutter_dva.dart';
import 'package:flutter_dva_hooks/flutter_dva_hooks.dart';
// --- Counter State ---
class CounterState extends DvaState {
CounterState({this.count = 0});
int? count;
@override
void fromJson(Map<String, dynamic> json) {
count = json['count'];
}
@override
Map<String, dynamic> toJson() => <String, dynamic>{'count': count};
}
// --- Counter Model ---
class CounterModel implements Model<CounterState> {
@override
String namespace = 'counter';
@override
StoreOfState<CounterState> state =
StoreOfState<CounterState>(state: CounterState());
@override
Map<String, ReducerFuction> reducers = <String, ReducerFuction>{
'increment': (StoreOfState<dynamic> lastState, DvaAction action) {
final current = lastState.state as CounterState;
current.count = (current.count ?? 0) + 1;
lastState.setState(current);
return lastState;
},
'decrement': (StoreOfState<dynamic> lastState, DvaAction action) {
final current = lastState.state as CounterState;
current.count = (current.count ?? 0) - 1;
lastState.setState(current);
return lastState;
},
};
@override
Map<String, EffectFunction> effects = <String, EffectFunction>{};
}
// --- Dva Initialization ---
final Dva dva = Dva(DvaOpts(
models: <Model<dynamic>>[CounterModel()],
));
void main() async {
WidgetsFlutterBinding.ensureInitialized();
WidgetCreatorFunction app = await dva.start(() => const MyApp(), () async {});
return runApp(app());
}
// --- App ---
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Dva Hooks Example',
theme: ThemeData(
colorSchemeSeed: Colors.indigo,
useMaterial3: true,
),
home: const CounterPage(),
);
}
}
// --- Counter Page (using useDvaConnect) ---
class CounterPage extends HookWidget {
const CounterPage({super.key});
@override
Widget build(BuildContext context) {
// useDvaConnect: subscribe to store changes and auto-rebuild
final connect = useDvaConnect(namespace: 'counter');
final count = (connect.state?['counter']?.state as CounterState?)?.count ?? 0;
final props = connect.props;
return Scaffold(
appBar: AppBar(title: const Text('Flutter Dva Hooks Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'useDvaConnect',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
Text(
'$count',
style: const TextStyle(fontSize: 48),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton.filled(
onPressed: () => props?.dispatch('decrement'),
icon: const Icon(Icons.remove),
),
const SizedBox(width: 16),
IconButton.filled(
onPressed: () => props?.dispatch('increment'),
icon: const Icon(Icons.add),
),
],
),
const SizedBox(height: 40),
const PropsDemo(),
const SizedBox(height: 40),
const StoreDemo(),
],
),
),
);
}
}
// --- Props Demo (using useDvaProps) ---
class PropsDemo extends HookWidget {
const PropsDemo({super.key});
@override
Widget build(BuildContext context) {
// useDvaProps: access dispatch without subscribing to changes
final props = useDvaProps(namespace: 'counter');
return Column(
children: <Widget>[
const Text(
'useDvaProps',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () => props.dispatch('increment'),
child: const Text('Dispatch via Props'),
),
],
);
}
}
// --- Store Demo (using useDvaStore) ---
class StoreDemo extends HookWidget {
const StoreDemo({super.key});
@override
Widget build(BuildContext context) {
// useDvaStore: access the store instance without subscribing
final store = useDvaStore();
final counterState = store.rootState['counter']?.state as CounterState?;
final count = counterState?.count ?? 0;
return Column(
children: <Widget>[
const Text(
'useDvaStore',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
Text('Count from store: $count'),
const SizedBox(height: 8),
FilledButton.tonal(
onPressed: () =>
store.dispatch(DvaAction('counter/increment', null)),
child: const Text('Dispatch via Store'),
),
],
);
}
}