flutter_hooks: React-Style Hooks for Flutter Widgets
React hooks for Flutter. Hooks are a new kind of object that manages a Widget life-cycles. They are used to increase code sharing between widgets and as a complete replacement for StatefulWidget.
At a glance
- What is it?
- flutter_hooks replaces StatefulWidget boilerplate with composable hook functions. Here is how the index-based mechanism works, how to install it, and where it breaks.
- Who is it for?
- Adopt flutter_hooks if you write Flutter widgets whose initState, didUpdateWidget and dispose blocks keep repeating, and you accept that hooks must run unconditionally in build. Do not adopt it if your state is shared across distant widgets or survives navigation; that is Riverpod's territory, and the README points to Riverpod as the state-management counterpart.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 125 days ago.
- What is it written in?
- Mainly Dart, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The StatefulWidget duplication problem flutter_hooks targets
The README opens with a concrete complaint: StatefulWidget makes it hard to reuse the logic inside initState, didUpdateWidget and dispose. Its worked example is an AnimationController. A widget that needs one must declare the controller, create it in initState with a vsync, update its duration in didUpdateWidget when the incoming widget field changes, and dispose it, all before build ever runs. Every widget that wants an AnimationController repeats that block, because none of it is shareable through normal inheritance.
The README also names Dart mixins as the existing workaround and lists two problems with them. A mixin can only be used once per class, so two independent AnimationControllers cannot both come from the same mixin. And a mixin shares the same object as the class, so two mixins declaring the same variable name produce anything from a compilation failure to unknown behaviour. flutter_hooks is presented as the third option, and its stated goal is narrow: increase code sharing between widgets by removing duplicates. It is not a state-management library for app-wide state.
How hooks are stored: a list on the Element, addressed by call index
The README explains the mechanism directly. Like State, hooks live in the Element of a widget, but instead of a single State the Element holds a List<Hook>. To use one you call Hook.use, and the hook you get back is selected by how many times use has already been called during that build. First call returns the first hook, second call returns the second, and so on.
The README includes a naive implementation to make the idea concrete. An index counter is reset at the start of every rebuild, and use increments it:
class HookElement extends Element {
List<HookState> _hooks;
int _hookIndex;
T use<T>(Hook<T> hook) => _hooks[_hookIndex++].build(this);
@override
performRebuild() {
_hookIndex = 0;
super.performRebuild();
}
}That index is the whole design. It is why the same hook can be called twice in one build and produce two independent AnimationControllers, both preserved across rebuilds, and it is also why the ordering rules exist. There is no name, no key and no identity beyond position. The README links to a React article on the same array approach, so this is a deliberate port rather than an independent design.
Rules you cannot negotiate: unconditional calls and use-prefixed names
Because hooks are resolved by index, the README states three rules. Prefix custom hooks with use, so readers know the call is a hook. Call hooks unconditionally. Never wrap a use call in a condition.
The reason is mechanical. If a conditional branch skips a hook on one build and takes it on the next, every later hook shifts by one position and receives the wrong stored state. The failure is not a crash with a clear message; it is state landing in the wrong hook. This is the same constraint React imposes, and it means flutter_hooks is a poor fit for code where the set of hooks depends on runtime data. If you find yourself wanting to conditionally create a controller, you create it unconditionally and decide inside the hook's own logic what to do with it.
The README's naming rule is easy to dismiss as style, but it carries information the type system does not. A function that returns a value and calls Hook.use internally is a hook; a function that merely wraps one is not, and calling it outside build will not work.
Installing flutter_hooks and writing a first HookWidget
The README does not spell out an install command; the package is published on pub.dev, which the badges link to, and the repository keeps the package under packages/flutter_hooks. The README's own before-and-after example is the clearest first use. The StatefulWidget version needs a State class mixing in SingleTickerProviderStateMixin, plus initState, didUpdateWidget and dispose. The hook version is this:
class Example extends HookWidget {
const Example({super.key, required this.duration});
final Duration duration;
@override
Widget build(BuildContext context) {
final controller = useAnimationController(duration: duration);
return Container();
}
}The README states this is functionally equivalent to the long version: the controller is still disposed, and its duration still updates when Example.duration changes. What you should expect to see is that the lifecycle code has moved into useAnimationController, one of the hooks the README lists under Existing hooks. If you call useAnimationController twice in the same build, you get two independent controllers that survive rebuilds. The README also shows that repeated call directly:
Widget build(BuildContext context) {
final controller = useAnimationController();
final controller2 = useAnimationController();
return Container();
}Hot reload: what survives an edit and what gets hard-reset
The README addresses the obvious worry about index-based state: a hot reload that reorders hooks should corrupt everything. HookWidget overrides the default hot-reload behaviour to work with hooks, so ordinary edits are safe. The README's example edits a parameter and states that all hooks keep their state.
The failure case is removal. The README walks through a build calling useA, useB(0) and useC, then shows the same build after useB is deleted:
useA();
useC();The README states plainly that useA keeps its state while useC gets a hard reset, because the index that used to belong to useC now belongs to useB's slot. This is a development-time behaviour, not a production one, but it is the kind of thing that produces a confusing debugging session if you do not know it. Inserting a hook in the middle of a build has the same class of effect on everything below it. The README does not document a way to preserve state across such an edit, and it does not describe a rollback path.
Where flutter_hooks is the wrong tool, and what Riverpod does differently
flutter_hooks scopes state to a widget's Element. That is the right scope for an AnimationController, a TextEditingController, or a scroll position. It is the wrong scope for state two distant widgets must share, or state that should outlive the widget that created it. A hook cannot solve that, because the list lives inside one Element.
The README does not present Riverpod as a competing implementation of the same idea; the related search terms pair the two constantly, but they operate at different levels. Riverpod is a state-management and dependency-injection layer: providers live outside the widget tree, are read from anywhere, and can be shared, overridden in tests, and kept alive across rebuilds. flutter_hooks is a widget-lifecycle tool. The two are frequently used together, which is why searches like flutter hooks vs riverpod tend to return setups that include both rather than a choice between them. If your problem is "this logic is duplicated across widgets," flutter_hooks addresses it. If your problem is "these widgets disagree about the current user," it does not, and no amount of hook composition will change that.
Maintenance, licence and the cost of upgrading
The repository is not archived, and the last push was on 2026-05-27. The README shows translated documentation for Portuguese, Korean, Simplified Chinese and Japanese, which suggests a maintained documentation surface, and the pub.dev badge tracks published versions. No recent release information was retrieved, so the release cadence cannot be described here.
Licence is MIT, which permits commercial use, modification and redistribution provided the copyright notice and permission notice are included. That is a permissive licence with no copyleft obligation on your application code. This is not legal advice; check the LICENSE file in the repository root for the exact terms.
The upgrade cost is concentrated in one place: hook call order. Because state is keyed by index, any change to the number or order of hooks in a build changes what stored state each call receives. Adding a hook at the end of a build is safe. Inserting one in the middle, or removing one, is not, and the README documents the reset that follows. In a codebase where builds are long and hooks are numerous, that makes refactoring a build method a deliberate act rather than a casual edit.
Editorial conclusion
Adopt flutter_hooks if you write Flutter widgets whose initState, didUpdateWidget and dispose blocks keep repeating, and you accept that hooks must run unconditionally in build. Do not adopt it if your state is shared across distant widgets or survives navigation; that is Riverpod's territory, and the README points to Riverpod as the state-management counterpart. Before committing, verify how your own hooks behave after a hot-reload that removes one of them, because the README states that removing a hook hard-resets every hook after it.
Frequently asked questions
What is flutter_hooks?
It is a Flutter implementation of React hooks, where hooks are objects that manage the lifecycle of a Widget. The README states their purpose is to increase code sharing between widgets by removing duplicates, and that they can serve as a complete replacement for StatefulWidget.
flutter_hooks vs StatefulWidget: what is the difference?
The README's AnimationController example shows the difference: the StatefulWidget version needs a State class with initState, didUpdateWidget and dispose, while the HookWidget version calls useAnimationController inside build and is stated to be functionally equivalent. The lifecycle logic moves into the hook rather than disappearing.
How do I install flutter_hooks?
The package is published on pub.dev, which the README's badge links to, and the repository keeps it under packages/flutter_hooks. The README does not give an install command, so follow the standard pub.dev workflow for the package.
Does hot reload break flutter_hooks state?
The README states that HookWidget overrides the default hot-reload behaviour to work with hooks, so editing a hook parameter preserves all state. Removing a hook is different: the README says the hooks before it keep their state while the hooks after it get a hard reset.
Why must flutter_hooks be called unconditionally?
Hooks are obtained from their call index, so the first call returns the first hook and the second returns the second. The README's rules say to call hooks unconditionally and never wrap a use call in a condition, because a skipped call shifts every later hook to the wrong stored state.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rrousselgit-flutter-hooks)