use-jolt-setup
Implements a Vue-style composition model for Flutter widgets using `setup` functions and reactive hooks.
Install
mkdir -p .claude/skills/use-jolt-setup && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/16252" && unzip -o skill.zip -d .claude/skills/use-jolt-setup && rm skill.zipInstalls to .claude/skills/use-jolt-setup
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Use when building Flutter widgets in a setup-once / hooks-driven composition style — declaring signals, controllers, listenables, effects, timers, and lifecycle callbacks through `use*` hooks inside a `setup` function that runs once, owns and disposes those resources, and returns a builder for reactive rebuilds. Provides SetupWidget, SetupMixin (on existing StatefulWidget), and SetupBuilder.Key capabilities
- →Manage widget lifecycle and state with `SetupWidget`
- →Extend existing `StatefulWidget` with `SetupMixin`
- →Use `SetupBuilder` for local composition and leaf widgets
- →Declare long-lived resources (signals, controllers, effects) with `use*` hooks
- →Ensure automatic disposal of resources when widgets unmount
How it works
The skill provides `SetupWidget`, `SetupMixin`, and `SetupBuilder` to manage widget lifecycle. A `setup` function runs once to declare resources using `use*` hooks, and a builder function handles reactive rebuilds, with resources automatically disposed on unmount.
Inputs & outputs
When to use use-jolt-setup
- →Creating reactive Flutter widgets
- →Managing long-lived widget resources
- →Implementing hooks-driven Flutter state
About this skill
Use Jolt Setup
package:jolt_setup/jolt_setup.dart brings a Vue/React-style composition model to Flutter on top of Jolt. A widget has two phases:
- Setup phase — a
setupfunction runs once per widget identity. Inside it,use*hooks declare every long-lived resource: signals, controllers, listenables, effects, timers, lifecycle callbacks. The setup function returns aWidgetFunction(() => Widget) that closes over those resources. - Build phase — the returned builder is invoked on every rebuild. Reactive reads (
signal.value,controller.value, etc.) inside the builder are tracked through aPostFrameEffect, so changes coalesce to one rebuild at frame end.
The package re-exports package:jolt_flutter/jolt_flutter.dart, so Signal, Computed, Effect, JoltBuilder, PostFrameEffect, .listenable / .notifier, etc. come along.
All hooks live in references/hooks.md. This file focuses on the three entry surfaces that own a setup runtime: SetupWidget, SetupMixin, and SetupBuilder.
Choosing an Entry Surface
| Situation | Use |
|---|---|
New widget; want a dedicated immutable widget type and reactive props | SetupWidget<T> |
Existing StatefulWidget whose State<T> you must keep (custom methods, mixins, external API) | SetupMixin<T> |
| Local composition, prototypes, leaf widgets — no need for a named widget class | SetupBuilder |
All three share the same setup model below; they only differ in how they bind a setup callback to the Flutter element tree.
The Setup Runtime (shared by all three)
Every entry surface creates a SetupContext that:
- Holds an
EffectScopeso signals/effects created during setup are automatically disposed when the widget unmounts. - Records the ordered list of hooks registered through
useHook/use*. Hot reload reuses hooks by sequence position and runtime type; a mismatch unmounts the tail and re-mounts new hooks. - Owns a
PostFrameEffect"renderer" that wraps the returned builder. Reactive reads inside the builder track this effect, so dependency changes schedulemarkNeedsBuildat frame end. - Forwards Flutter element lifecycle (
didUpdateWidget,didChangeDependencies,activate,deactivate,unmount,reassemble) to each hook, in registration order on activate, reverse order on deactivate/unmount. - Exposes
resetSetup()— schedules a full setup rerun at frame end (tears down hooks + renderer, runssetupagain). Use only when the initialization boundary itself must rebuild; ordinary state changes belong in signals/effects.
Implication: don't put conditional use* calls behind if / loops that can change between rebuilds, and don't call use* outside setup — the hook index must be stable. (Bare reactive reads through .value happen in the builder, not in setup itself, unless you want them as setup-time dependencies of an effect/computed.)
SetupWidget<T>
A new widget base class. Override setup(BuildContext context, Props<T> props); the returned WidgetFunction<T> is the builder. Props<T> is a reactive view of the current widget instance — read props() or props.value to subscribe to widget-field changes from the parent.
class CounterCard extends SetupWidget<CounterCard> {
const CounterCard({
super.key,
required this.title,
required this.initialValue,
});
final String title;
final int initialValue;
@override
setup(context, props) {
final count = useSignal(props().initialValue);
final label = useComputed(() => '${props().title}: ${count.value}');
onMounted(() => debugPrint('mounted: ${props().title}'));
return () => GestureDetector(
onTap: () => count.value++,
child: Text(label.value),
);
}
}
Use SetupWidget when the component has a clear identity (constructor fields, public API) and parent updates to those fields should flow into setup-owned state through props.
SetupMixin<T> (on State<T>)
Mixes into an existing State<T> subclass. Override WidgetFunction<T> setup(BuildContext context); access widget fields via the mixin getter props (reactive) or widget (plain Flutter). All State lifecycle and instance methods remain available — the mixin only adds the setup runtime on top.
class _WelcomePanelState extends State<WelcomePanel>
with SetupMixin<WelcomePanel> {
late AnimationController controller;
void show() => controller.forward();
void hide() => controller.reverse();
@override
setup(context) {
controller = useAnimationController(
duration: const Duration(milliseconds: 250),
);
return () => Column(
mainAxisSize: MainAxisSize.min,
children: [
FadeTransition(opacity: controller, child: const FlutterLogo(size: 72)),
Row(children: [
FilledButton(onPressed: show, child: const Text('Show')),
OutlinedButton(onPressed: hide, child: const Text('Hide')),
]),
],
);
}
}
Use SetupMixin when you must keep a custom State<T> — e.g. to expose instance methods to a GlobalKey, mix in other State mixins, satisfy a base class, or migrate an existing widget incrementally.
Important: setup runs on first build, not in initState, because hooks may read inherited widgets (Theme.of(context) via useInherited). Override initState only for work that does not depend on setup-owned state.
SetupBuilder
A SetupWidget<SetupBuilder> constructed from an inline callback. No widget class needed; the setup callback receives BuildContext (no typed props, since the widget identity is SetupBuilder itself).
SetupBuilder(
setup: (context) {
final count = useSignal(0);
useEffect(() => debugPrint('count = ${count.value}'));
return () => FilledButton(
onPressed: () => count.value++,
child: Text('Count: ${count.value}'),
);
},
)
Use SetupBuilder for local composition, reactive leaf widgets in larger build methods, prototypes, or anywhere the cost of declaring a SetupWidget subclass outweighs its benefit. Each SetupBuilder in a parent build is a separate widget identity and gets its own setup runtime.
Hooks at a Glance
Hooks are top-level use* functions (or use*.variant(...) factories) that must be called inside a setup function. They fall into a few buckets:
- Reactive primitives —
useSignal(+.lazy/.list/.map/.set/.iterable/.async),useComputed(+.withPrevious/.writable/...),useEffect,usePostFrameEffect,useWatcher(+.immediately/.once),useEffectScope,useUntil(+.when/.changed). - Lifecycle callbacks —
onMounted,onUnmounted,onDidUpdateWidget,onDidChangeDependencies,onActivated,onDeactivated. - Context & memo —
useContext,useSetupContext,useInherited,useMemoized,useAutoDispose,useHook(+SetupHook<T>for custom hooks). - Flutter controllers — text/scroll/page/tab/animation/focus/etc. (auto-disposed).
- Listenable & sync bridges —
useValueNotifier,useChangeNotifier,useListen.{value,listenable,stream}(+.watch),useSync.{from,bidi}. - Async —
useFuture(+.watch),useStream(+.watch),useStreamController(+.broadcast). - Misc —
useTimer(+.periodic),useAppLifecycleState,useAutomaticKeepAlive(+.value), experimentaluseSetupResetfamily.
Full signatures, variants, lifecycle behavior, and examples are in references/hooks.md. To write your own hook — function-style, class-style (SetupHook<T>), or extension-style attached to a built-in creator like useSignal.myThing — see references/custom-hooks.md.
Rules
- Call
use*only at the top level ofsetup— never inside conditionals, loops, callbacks, or after early returns. The hook index must be stable across rebuilds. - Return only the
() => Widgetfromsetup. Don't return computed widgets directly; let the builder close over reactive state so rebuilds work. - Long-lived resources belong in hooks (
useSignal,useMemoized, controller hooks); they auto-dispose. Don'tnewthem insetupwithout a hook unless you also handle disposal viaonUnmountedor anEffectScope. - Use
props()(SetupWidget) or thepropsgetter (SetupMixin) when setup-owned state must react to parent updates; rawwidget.fooreads insetupare captured only at the first run. resetSetup()is a heavy escape hatch (rebuilds the whole hook sequence). Prefer ordinary signal updates.- Reading inherited widgets inside
setup: useuseInherited((c) => Theme.of(c))so dependency changes invalidate the cached value reactively. PlainTheme.of(context)works too but isn't reactive past the initial setup.
Source Navigation
Read source before answering API-sensitive questions.
| Area | Path |
|---|---|
| Public exports | packages/jolt_setup/lib/jolt_setup.dart |
SetupContext, SetupHook, lifecycle plumbing | packages/jolt_setup/lib/src/setup/framework.dart |
SetupWidget, SetupBuilder, SetupWidgetElement | packages/jolt_setup/lib/src/setup/widget.dart |
SetupMixin | packages/jolt_setup/lib/src/setup/stateful_mixin.dart |
| Built-in hooks | packages/jolt_setup/lib/src/hooks/ |
| Example | packages/jolt_setup/example/jolt_setup_example.dart |
| Tests | packages/jolt_setup/test/ |
When not to use it
- →When building Flutter widgets without a setup-once / hooks-driven composition style
- →When the user needs to call `use*` hooks inside conditionals or loops
- →When the user needs to manage state outside of the Flutter element tree
Limitations
- →The skill is for building Flutter widgets.
- →The skill uses a setup-once / hooks-driven composition style.
- →The skill requires `use*` calls only at the top level of `setup`.
How it compares
This skill introduces a hooks-driven composition model for Flutter widgets, centralizing resource declaration and disposal in a single `setup` function, which differs from traditional `StatefulWidget` management.
Compared to similar skills
use-jolt-setup side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| use-jolt-setup (this skill) | 0 | 2mo | No flags | Advanced |
| flutter-development | 1,555 | 5mo | No flags | Intermediate |
| flutter-expert | 73 | 4mo | No flags | Advanced |
| flutter | 13 | 4mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
flutter-expert
sickn33
Master Flutter development with Dart 3, advanced widgets, and multi-platform deployment. Handles state management, animations, testing, and performance optimization for mobile, web, desktop, and embedded platforms. Use PROACTIVELY for Flutter architecture, UI implementation, or cross-platform features.
flutter
alinaqi
Flutter development with Riverpod state management, Freezed, go_router, and mocktail testing
mobile-developer
sickn33
Develop React Native, Flutter, or native mobile apps with modern architecture patterns. Masters cross-platform development, native integrations, offline sync, and app store optimization. Use PROACTIVELY for mobile features, cross-platform code, or app optimization.
stac-quickstart
StacDev
Help initialize and validate a Stac-enabled Flutter project and ship a first server-driven screen. Use when users ask to set up Stac CLI, run stac init/build/deploy, verify project prerequisites, or troubleshoot first-run setup and missing configuration files.
webf-native-plugins
openwebf
Install WebF native plugins to access platform capabilities like sharing, payment, camera, geolocation, and more. Use when building features that require native device APIs beyond standard web APIs.