Flutter Hooks

Kefeh Collins
Flutter Community
Published in
5 min readJul 23, 2021

So today we are having a look at a state management approach that is just a step above Stateful widgets. This is in fact a very good and easy to grasp method for those coming from the web (react.js) and those who want to engulf themselves in a functional simplistic approach to state management.

In our previous article, (stateful widgets) we saw in detail what stateful widgets are and how they helped us to manage state.

We saw that a stateful widget is made up of a widget class and a state class, and in the state class, we defined the mutable properties, and we often mutate them inside the setState to be able to trigger the rebuild of the layout.

There seems to be too much boilerplate code and information to keep track of to effectively make use of stateful widgets.

Let’s take a look at flutter hooks as an alternative to stateful widget and see how that works on our BlueSquare example.

Flutter hooks is a community package and so needs to be added to our project as a dependency. You can check it out here to add to your pubspec.yaml file

With stateful widgets, we saw that we needed two classes, one for the widget and the other for the state. We needed to define the mutable properties of the widget in the state class and then use setState to mutate them and trigger a rebuild.

What if we could have all those hassles handled for us while being encapsulated?

Wow, the code is simplistic and straight to the point.

We have our widget class look like any other stateless widget but for the fact that it extends the HookWidget class, this class gives us access to all the hooks needed to make our project come to life and in our case, we are using the useState hook. The useState is a valueNotifier that creates valueNotifier.value and subscribes to it such that whenever that value is updated, it marks the HookWidget as needing rebuild and so the build method is called (hence why we use clicks.value to access and update the value for our state).

From our new modified BlueSquare we can see how adding and using flutter hooks has reduced the amount of code we have written and removed the control of being accountable for our rebuilds to be handled by the value notifier.

But this is just a minimal look at the reduction of the boilerplate code that hooks provide as an advantage.

When we looked at stateful widgets, we saw that there were lifecycle methods like the initState, dispose and didChangeDependencies that were used to prepare code or values that the build function will depend on; things like listeners, controllers etc, hooks take away the boiler plate code that we need to be doing this, another thing is that most at times these listeners and controllers can’t be reused which means if we need more than one controller even of the same type, we will need to go through the same initialization and disposing of the controllers ourselves and this can be hassle and our code becomes cumbersome for no reason.

With just two controllers we are starting to see how cumbersome the code can be and if we are to add just one more controller, we will need to go through all the hassle again, defining, initializing and deposing. If we contrast this with the code that does the same thing with hooks, we see a big difference in the amount of code.

And with just this small amount of code, we are able to achieve the same fit of work. The useAnimationController creates an AnimationController that is already disposed of and initializes it with the values provided.

Let’s modify our BlueSquare to scale down to 80% of its size every time it is clicked both hooks and stateful widget approaches. This example makes use of the useState and the useAnimationController we have seen before.

With hooks

With Stateful Widgets

We have seen just an example of two hooks, useState and useAnimationController, but there are quite a few other hooks provided from the flutter_hooks package some like:

  • useEffect(): which alongside the useState is used to initialize state data and most often could be used to replicate the function of initState and dispose.
  • useContext(): It returns the BuildContext of the HookWidget.
  • useTextEditingController(): Creates a TextEditingController and automatically takes care of disposing of it.
  • useTabController(): Creates a TabController and automatically takes care of disposing of it.
  • useStream<T>(): Subscribes to a Stream<T> and uses an AsyncSnapshot<T> to return the current state.
  • useFuture<T>(): Subscribes to a Future<T> and uses an AsyncSnapshot<T> to return the current state.

And many others, you can check out the documentation for more on that.

If you however check out the documentation and don’t find a hook that suits your purpose, you can create a custom hook for yourself and use it like any other hook.

So let’s say for instance that we needed our blue square to instead show some random numbers within the range of 0–9 every second, we could just create a hook for it.

And with that we have created our own custom hook ready for use on our project. Now let’s use it with the useRandomNumber() function.

And that’s how we can use our custom hook. The fortunate thing is that such a hook can be reused even in other classes and will save us a lot of effort.

Hooks give us the means:

  • Reduce redundant and cumbersome boilerplate code such as that in a stateful widget
  • Improve on our code usability as we can create and reuse hooks without any issues.

With that, we have come to the end of this part of our series. In the next series, we will be taking a deep dive into inherited widgets and how we can make the most out of them.

https://Twitter.com/FlutterComm

--

--

Kefeh Collins
Flutter Community

An Enthusiastic problem solver, uses code as a tool for problem solving.