The easy way to manage the state of Flutter using flutter_hooks
02-Oct-2023 - Sophoun
I saw a lot of people talking about state management in Flutter like bloc
, provider
, riverpod
, and others. But not of those people mention about flutter_hooks
package.
In this small blog post, I will explain to you how it's easy to just use only flutter_hooks
to manage your Flutter state.
flutter_hook
?In their page of flutter_hooks
the package on pub.dev you can see in the first line, they said:
And the second line said:
Widget
. They exist for one reason: to increase the code-sharing between widgets by removing duplicates.Yes, it exists for a reason. Flutter hooks are similar to react hooks as they've mentioned in the first line. If you're familiar with React it will be easy to help you but if not, that's okay. I will explain you in this blog.
Hooks is a state management solution for React applications and it's easy to use. Then someone in the Flutter community brought this technique to the Flutter echo system.
In Flutter everything is a widget this way is similar to React, everything is a React component.
To start using flutter_hooks
you have to add dependencies to your pubspec.yaml
file like below.
dependencies: flutter_hooks: ${latest_version}
Go to the package info page for more details: https://pub.dev/packages/flutter_hooks/install
After adding the dependency you can start using it.
Flutter Hook has its own special widget called HookWidget
all widgets that want to use hook must be extended to this widget and override build
function as normal.
Example:
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; class HomeWidget extends HookWidget { Widget build(BuildContext context) { // TODO: implement build throw UnimplementedError(); } }
After you extend to HookWidget
you can use other hook helper method to archive your state management.
Flutter_hooks has delivered with build-in some useful hooks like the below.
Name | Description |
---|---|
useEffect | Useful for side effects and optionally canceling them. |
useState | Creates a variable and subscribes to it. |
useMemoized | Caches the instance of a complex object. |
useRef | Creates an object that contains a single mutable property. |
useCallback | Caches a function instance. |
useContext | Obtains the BuildContext of the building HookWidget . |
useValueChanged | Watches a value and triggers a callback whenever its value changes. |
This is just a few, but in most case, you just need some 2 or 3 hooks to achieve your goal.
useState()
is the most common one that I always use. It helps us to hold the state when the flutter widget is rebuilt. See below
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; class HomeWidget extends HookWidget { const HomeWidget({super.key}); Widget build(BuildContext context) { final count = useState(0); return Scaffold( body: Center( child: Text("Count: ${count.value}"), ), floatingActionButton: FloatingActionButton( child: const Icon(Icons.add), onPressed: () { count.value++; }), ); } }
As you can see above it's really easy to use useState
hooks.
You start with the declaration of the state with the default value.
Access the state value in the text widget to display any changes.
Get the value and add it to the existing floating action button.
In the above example, build
the function will be rebuilt when you change the value of count
. But the count
the hook will hold your latest value in it during the rebuild. This is cool, right?
In some cases you just want the hook to call it once when the first widget is built. It could be an API call to display data on the screen, you don't need it to call again when it rebuilds. I will use the same example as above.
Example
import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; class HomeWidget extends HookWidget { const HomeWidget({super.key}); Future<String> getDummyJson() async { return (await http.get(Uri.parse("https://dummyjson.com/products?limit=1"))) .body; } Widget build(BuildContext context) { final result = useMemoized(() => getDummyJson()); return Scaffold( body: FutureBuilder<String>( future: result, builder: (context, snapshot) { return Center( child: Text("Result: ${snapshot.data}"), ); }, ), ); } }
In the above example, I have a helper function that calls dummyjson.com. This API will respond to a string of JSON value after it gets the result.
I declare function using useMemorized()
hook to ensure function call only one time during the widget lifecycle.
I access the value using FutureBuilder
to get the value from API.
Show result in Text widget.
As you can see it's easy to archive the tasks using flutter_hooks
package. If you're familiar with React you will be feeling at home at this point. I hope you will consider this package for your next project. If you want to get more detail about this package please check the package via this link: https://pub.dev/packages/flutter_hooks. Good bye, see you next time.