Transcript for:
Simplifying State Management with Flutter Hooks

did you ever feel dissatisfied writing logic inside your widgets just because that's how flutter is designed if you didn't don't worry you are still completely normal person and for those of you who did what if i told you you can swallow a blue pill and make most of it go away let me introduce you to flutter hooks hooks will solve two of your main issues boilerplate of stateful widget and sharing same code across in-state and dispose methods of your widgets remember less time you have to spend writing and maintaining code means more time for your friends family or your girlfriend boyfriend unless you don't have any of those then you should just probably skip this video anyways let's get started enter flutterpop get flutter underscore hooks into your console and wait for magic to do its work i promised you getting rid of boilerplate so let's do that first replace your stateful widget with stateless widget and change it into a hook widget if you ever used react hooks before you'll probably know what's coming next but for those of you who didn't bear with me hook is a reusable piece of code you can write your own hook or use one of the many predefined hooks which come with the package in either case there is a rule that hook must always be prefixed with use and called only in build method of a widget one of the most useful predefined hooks is use effect it takes a function as a first parameter and gives you an option to return another function as a return value second parameter is a list of variables which if changed will cause use effect hook to execute again leaving second parameter as empty array will make sure code runs only once so what we have here is basically init state and dispose without usual boilerplate let's start the app and convince ourselves that is really the case we can also have multiple instances of the same hook containing different code which is great they will both run in the order you define them hooks are basically pieces of code stored in a list in your widget but instead of sharing same state with the widget each one of them runs in isolation for that reason hooks should never be called inside conditions and finally let's see what happens if we change variable listed in second parameter notice that code in other use effect hook didn't get called but the one with change perimeter did by now you must probably be thinking use effect is a good place to initialize and dispose my streams texted it in controllers or run any initialization code that is correct but people from flutterhook's community have foreseen that and created more specialized hooks which will make your life even more easier another hook you'll probably find handy is use text editing controller text editing controller is one of those resources that need to be created and disposed manually but when used as a hook disposing it is automatic also the boiler plate of creating stateful widget just to dispose text editing controller is gone and everything looks more neat and readable in addition there are hooks for similar controllers like tab controller page controller and scroll controller for example if we want to change tabs programmatically using tab controller this is the code we'd have to write down in order to make it work we can achieve the same thing using ustep controller hook with far less code in case we need to do some initialization like adding a listener to a controller we can do it inside use effect hook i hope this gives you an idea how hooks can work together now let's move on to use statehook use state will require a generic argument which is your initial state this can obviously be any basic type but also an object for sake of simplicity let's use a boolean state which will toggle visibility of an element when we click on a button let's run demo to make sure example works as expected clicking on button indeed changes our boolean state and text elements visibility is changing too use state hook is actually a value notifier which means we access its state from the value parameter this works great but notice that we are rebuilding whole widget for something that actually takes place significantly lower in the tree we could easily solve this problem by extracting everything under sized box widget to another widget and this is actually recommended so called flutter way but in some instances you might not want to do that either when widget is too simple like this one or for the sake of readability in that case you can isolate what gets rebuilt by using widget called hook builder you can put hook builder anywhere in your tree and call a hook from its builder method another way to approach this problem is by using use value node to fire hook the difference between these two hooks is that use state immediately notifies or rebuilds when state changes while use value notifier doesn't this way we can keep state reference in the top widget and rebuild only those child widgets which are listening to it we can listen to changes with use value listenablehook now let's move to a more realistic example sooner or later you need to access some kind of api with your app and display the result in your widget you will hopefully be very uncomfortable with putting that kind of code in your widget and instead create a separate class to honor separation of concerns principle once you do that you'll need to call those api functions somewhere in your widget like unpressed method of a button that means you need a reference to api class on a top widget level which can be achieved with use memoized hook in use memoize hook you can instantiate your big objects which are going to be cached between widget rebuilds second parameter also takes lists of values which if changed will force new instances of object to be created now we can use concrete method from our api class to fetch some data we'll hook it into a future builder since the method we are calling returns future when the widget loads so will data from our api call which is great what if we want to get fresh data at some point in the future we could store function call into a value notifier hook and wrap future builder with the hook builder we'll subscribe to changes by calling use value listenable and each time there is a change new feature will be obtained and passed to a future builder by assigning same api function call to a value notifier we are basically triggering a rebuild with the same function but different result if you're thinking that's a bit weird workaround to do something simple like calling a function you're right the thing is flutter hooks wasn't meant to be some sort of state management solution by default the main purpose of this package is to increase code sharing between widgets and reduce boilerplate for that reason flutterhook's package is often used with river pot redox block or any other proper state management packages there is also a way to do state management only with flutter hooks but this will be a topic for the future video one case where hooks shine the most are the animations by now you have probably found yourself in a situation where you need a custom animation that is not available as one of the existing animation widgets having that meant turning your previously stateless widget into a stateful widget just so you can create and dispose animation controller let's take a look at simple example of record button with animated shadow first we need to define animation controller and set some duration and direction we can store animation object using use memoized hook because there's no need to get new instance of this resource every time widget rebuilds and finally we'll define recording state now animation can be assigned to animation builder and values to animate shadow can be obtained from animation object inside unpressed method of a button will toggle recording state which will render appropriate icon and shadow let's run this demo and see if it works clicking on record starts animation and shows stop icon just as expected clicking stop will remove shadow and render record button we can expand this example with one more widget let's suppose we want to display elapsed time since recording started and reset it when recording is stopped to make things more readable we'll extract button widget and create new elapsed time label widget since those widgets will both depend on recording state we can wrap them together with hook builder widget and pass the state down to their constructors elapsed time label widget will consist of simple text widget wrapped invisibility widget we can hook recording state value to its visibility field next thing we'll need is some kind of timer which will periodically update text widget one important thing we have to keep in mind is we'll have lots of free builds depending on timer period we specify we definitely don't want to rebuild more times in maximum frames per second our device can push luckily there is something called single ticker provider which solves that issue and is already available as a built-in hook next we need to create actual ticker object which will use sticker provider a sticking source and update state after every frame elapses now that we have thicker object we also need to make it stick we can do that in use effect hook we'll also have to make sure code is re-run after recording state changes by adding recorder dot value to the dependency list of use effect hook ticker should also eventually be disposed so we'll need another use effect hook and make sure it runs only once and only on dispose now we have all resources ready so let's plug state to the text widget and run example you might have noticed that we had to write a bit more code to make all this work which made our widget filled with logic last thing we want to do is define all the principles we were fighting using flutter hooks but fear not my friends because we can extract audit logic into a custom hook in a separate file creating custom hook couldn't be easier all you have to do is create function and copy all the logic inside it make sure your hook name starts with use and returns resource you are interested to in this case we'll return duration now we can replace all of our code in widget build method with only one line also you can use the hook in any other widget if you need to and that's it folks enjoy your fish