Flutter Hooks
jolt_hooks is built on flutter_hooks, providing Flutter with a Hook API deeply integrated with the Jolt reactive system. It allows developers to elegantly use all of Jolt's reactive features in HookWidget while enjoying the automatic lifecycle management benefits of Flutter Hooks.
By encapsulating Jolt's reactive primitives (such as Signal, Computed, Effect, etc.) as Hooks, developers can directly create and manage reactive state in functional components. These Hooks automatically clean up resources when Widgets are unmounted, eliminating the need for manual dispose logic and greatly simplifying state management work.
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:jolt_hooks/jolt_hooks.dart';
class CounterWidget extends HookWidget {
@override
Widget build(BuildContext context) {
final count = useSignal(0);
final doubled = useComputed(() => count.value * 2);
return Scaffold(
body: HookBuilder(
builder: (context) => useJoltWidget(() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Count: ${count.value}'),
Text('Doubled: ${doubled.value}'),
ElevatedButton(
onPressed: () => count.value++,
child: Text('Increment'),
),
],
);
}),
),
);
}
}useSignal
useSignal is an instance of JoltSignalHookCreator for creating reactive signals. Usage is the same as Signal, only the construction method differs, and it supports the keys parameter.
final count = useSignal(0);
final name = useSignal('Alice', keys: [userId]); // Recreates when userId changesExtension Methods
useSignal.lazy(): Create lazily initialized signaluseSignal.list(): Create list signaluseSignal.map(): Create map signaluseSignal.set(): Create set signaluseSignal.iterable(): Create iterable signaluseSignal.async(): Create async signaluseSignal.persist(): Create persistent signal
All extension methods support the keys parameter.
useComputed
useComputed is an instance of JoltComputedHookCreator for creating computed values. Usage is the same as Computed, only the construction method differs, and it supports the keys parameter.
final firstName = useSignal('John');
final lastName = useSignal('Doe');
final fullName = useComputed(() => '${firstName.value} ${lastName.value}');Extension Methods
useComputed.writable(): Create writable computed valueuseComputed.convert(): Create type-converting computed value
All extension methods support the keys parameter.
useJoltEffect
useJoltEffect is an instance of JoltEffectHookCreator for creating side effects. Usage is the same as Effect, only the construction method differs, and it supports the keys parameter.
final count = useSignal(0);
useJoltEffect(() {
print('Count changed to: ${count.value}');
});Extension Methods
useJoltEffect.lazy(): Create a deferred effect; callrun()before it starts tracking dependencies
useWatcher
useWatcher is an instance of JoltWatcherHookCreator for creating watchers. Usage is the same as Watcher, only the construction method differs, and it supports the keys parameter.
final count = useSignal(0);
useWatcher(
() => count.value,
(newValue, oldValue) {
print('Changed from $oldValue to $newValue');
},
);Extension Methods
useWatcher.immediately(): Create immediately executing watcheruseWatcher.once(): Create watcher that auto-disposes after one execution
All extension methods support the keys parameter.
useEffectScope
useEffectScope is an instance of JoltEffectScopeHookCreator for creating effect scopes. Usage is the same as EffectScope, only the construction method differs, and it supports the keys parameter.
useEffectScope(fn: (scope) {
scope.run(() {
final count = Signal(0);
Effect(() => print('Count: ${count.value}'));
});
});useJoltStream
Convert reactive values to Dart Streams. Usage is the same as the stream extension, only the construction method differs, and it supports the keys parameter.
final count = useSignal(0);
final stream = useJoltStream(count);useJoltWidget
Use reactive Widgets in HookBuilder. When signals accessed in the Widget build function change, the Widget automatically rebuilds.
Important: This Hook must be used inside HookBuilder.
Widget build(BuildContext context) {
return HookBuilder(
builder: (context) {
final counter = useSignal(0);
return useJoltWidget(() {
return Column(
children: [
Text('Count: ${counter.value}'),
ElevatedButton(
onPressed: () => counter.value++,
child: Text('Increment'),
),
],
);
});
},
);
}keys Parameter
All Hooks support the keys parameter for Hook memoization. When keys change, the Hook is recreated:
final count = useSignal(0, keys: [userId]); // Hook is recreated when userId changesLifecycle Management
All reactive objects created through Hooks are automatically disposed when Widgets are unmounted, without needing to manually call dispose().
Integration with JoltBuilder
You can also use JoltBuilder from the jolt_flutter package to implement reactive UI updates:
import 'package:jolt_flutter/jolt_flutter.dart';
Widget build(BuildContext context) {
final count = useSignal(0);
return JoltBuilder(
builder: (context) => Text('Count: ${count.value}'),
);
}Important Notes
Hook Rules: All Hooks must be called in the
buildmethod ofHookWidgetor thebuilderofHookBuilder, and cannot be called in conditional statements or loops.useJoltWidget Limitation:
useJoltWidgetmust be used insideHookBuilderand cannot be used directly in regularHookWidget.Automatic Cleanup: All resources created through Hooks are automatically cleaned up when Widgets are unmounted, without manual management.
keys Parameter: Using the
keysparameter can control when Hooks are recreated, which is useful for scenarios dependent on external parameters.
Related APIs
- Signal - Learn about basic signal usage
- Computed - Learn about computed property usage
- Effect - Learn about side effect usage
- SetupWidget - Learn about SetupWidget and Flutter resource Hooks