Flutter State Management - The Grand Tour

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Nice informative vid at a good pace.

👍︎︎ 2 👤︎︎ u/KimPaow 📅︎︎ Mar 15 2019 🗫︎ replies
Captions
[Music] state management for whatever reason is a topic that brings out strong opinions and developers I'm gonna have to go ahead and sort of disagree with you there in today's video we'll look at 10 different ways to build a basic counter app using different state management strategies employer we'll also just talk about what state management is and why there are so many different ways to approach it and hopefully by the end of this video you know exactly where strategy is ideal for your app if you're new here like and subscribe and you grab the full source code on fire ship IO and I'm giving away another t-shirt with this video just leave me a comment with your own opinions about state management below first of all what is stake in a reactive framework like flutter you can think of your UI as the return value of a function that function gets called with one argument which is your state so state is just data that changes over the lifecycle of your app a lot of your data can be self-contained within a single widget that's known as local state we'll look at the tools that we have built into flutter to manage local state which is pretty straightforward things get interesting when we start talking about global state or state that needs to be shared throughout the widget tree coming from the web development world I've seen tons of debate over state management and a lot of apps over engineered with these big state management libraries that didn't really need them that's not to say they're not valuable but even the creators and maintainer of those libraries will tell you that you probably don't need them we'll talk about the pros and cons of these various libraries as we go but for now let's focus on the fundamental building blocks in flutter starting with the stateful widget when you run flutter create from the command line it gives you some starter code that increments a counter with a stateful widget we're going to rebuild this counter multiple times throughout this video using different state management strategies to create a stateful widget we need two classes the first one is the stateful widget itself and that implements a create state method and that returns our second class which is an extension of the state class and this is where all the heavy lifting happens first we define a property called counter which is an integer that defines the actual data state of this widget then we define a method called increment counter and it calls a method called set state which will tell this widget to re-render when this value changes after that we implement the build function which defines the actual widgets that will be rebuilt every time set state is called I've stripped these down to the bare minimum we just have a text widget that will display the current value of the counter and we have a floating action button that will increment the counter when pressed stateful widgets are great for managing local state but there's a couple things I don't like here first of all we have to define two separate classes which is sort of confusing and adds boilerplate and I know from experience with react j/s that coin set state all over the place does not scale very well it's fine when we just have one property but you can imagine how this would become a mess if we had 20 different properties on this widget to update and with that I'll move on to topic number two a stateful builder there's a variety of different builder widgets in flutter that allow you to react to different types of changes one of those a stateful builder which will allow us to simplify our stateful widget code notice this time we're starting by extending a stateless widget and then we'll define our state as a counter that starts at zero then the first widget that will add to our build method is a stateful builder and that takes a builder function that function gives us access to the build context and also a function called set state when we call set state it will tell the stateful builder to rebuild all the widgets inside this function and they'll look pretty much identical to the previous example where we have text for the counter value and then a floating action button to increment it now I want to point out that I'm kind of breaking the rules in flutter that's why you see this green squiggly line under the class name this class is immutable which means the properties on it should never be reassigned and we're violating that by incrementing the counter so if you use a stateful builder within a stateless widget I would recommend setting up your data as a map or a list because you can mutate values in those data structures without breaking the contract of the stateless widget but overall the stateful builder is a nice little tool that helps you avoid the boilerplate of a stateful widget and is really ideal when you have simple local state management to deal with but now things are going to start getting interesting because we're going to talk about app state or global state in flutter it's possible to pass data from top to bottom or from parent to child but it's not really practical to pass data the other way around from child back to parent or from sibling to sibling but almost every non-trivial app is going to have some kind of shared state at one point or another that runs into this limitation the first thing I want to show you is inherited widget now I don't recommend using this as a state management solution because there are better alternatives that already do it for you but it's important to know how it works because it's a fundamental building block in flutter that's implemented in many other features of the framework basically it's a widget that allows you to pass context to any of its descendants no matter how far nested they are in the widget tree so the first thing you'll usually do is put the inherited widget towards the top of the widget tree which we've done here with our inherited counter and then we have our actual homepage as a child of that inherited widget our inherited counter will extend the inherited widget built into flutter and it will take a child widget as an argument to its constructor from there we're going to override a method called update should notify and this will run when this inherited widget is rebuilt and will notify any descendents whether or not they need to rebuild I'm just setting it to true but you could look at the different the widget actually needs to re-render and then it's conventional to also implement a static method called of thing calls inherit from widget of exact type with the inherited counter type now the inherited widget is immutable so we could wrap it in a stateful widget to tell it when to rebuild but for the sake of simplicity I'll just go ahead and define our counter data as a map this is a private variable so first we'll go ahead and define an increment method which allows us to increment the counter value and then we'll add a getter to get the current value from the map now that we have that setup we can go down here and define our state list widget home page now just for convenience I'm using the example we had set up previously with our stateful builder and inside that builder method we can access the value from the inherited counter by calling of context with the values from that class now this may look trivial in this example but if you imagine our homepage was nested 20 levels deep it could still access these values without having to directly pass anything through each constructor in the widget tree now like I said earlier you probably don't need to mess with inherited widgets directly and you'll see why later in this video because there's already libraries that do similar things in a much less awkward way but before we get to that point I want to show you my personal favorite way to manage global State in a flutter app and that is to leverage a special type of stream and rx dart called a behavior subject we'll start by creating our own custom class and then give it a private value that's set to a behavior subject that starts at 0 these are incredibly useful for state management for a variety of reasons first of all they always have a current value that we can read and flutters build methods but at the same time we can treat them as a stream and a stream that we can control by adding new values to it and it's a broadcast stream by default so multiple widgets can listen to the same stream this allows us to implement our own business logic related to the flow of data for the stream and we can do it completely independent of the widget tree that makes it much easier to test in isolation and also just easier to reason about now we can define our own custom API that our widgets can consume for example if we want to expose the stream we can just call counter stream then we can also create a getter that grabs the current value synchronously from the behavior subject and then we'll define a method to mutate the behavior subject called increment which just adds a new value to the stream and that's basically all it takes to build your own custom state management solution that all of your widgets can react to and share now I'm going to just instantiate it in the global namespace which is kind of frowned upon but I'll show you an alternative to this in just a minute now that we have access to this counter service globally we can rebuild that homepage widget in the build method we'll start with a scaffold and then as the body will add a stream builder then we'll pass it the stream from our behavior subject so now every time we add a new value to the behavior subject this widget will rebuild and one minor thing that you might have missed is that we're able to mess this stream builder deeper in the widget tree and that means we're repainting less of the UI than we were in previous examples it's not a big deal here but it could be if you have a lot of widgets nested in the scaffold the next thing we'll do is implement the Builder function for that we'll just return our text and that will have a snapshot of the current count or the current data from the stream and the actual etc that data is completely decoupled from the stream builder which means we can add it outside of the build context so it doesn't need to rebuild whenever the actual value of the stream changes and another bonus of a stream builder is that it will automatically unsubscribe from the stream when the widget is disposed that means you don't need to manually cancel streams to avoid memory leaks this is really nice and flexible but I'd like to get this applicable namespace and use it in a way that's more like a true singleton for that I'm going to register it with a library called gedit we'll go ahead and import that library and then instantiate get it then we'll go into our main function and call register singleton pass in the type counter and then instantiate the counter now we can use our counter state in any widget that requires it this makes the state easier to mock for integration tests and guarantees that you won't accidentally instantiate the counter class more than once if you're an angular developer I definitely think you'll like this pattern but now it's time to move on to the next strategy the block pattern now we could implement this entirely from scratch but I highly recommend using the flutter block library under the hood it extends the inherited widget that we looked at earlier but it provides a much more intuitive way to pass state around the widget tree block is very similar to redux if you've ever worked with react it provides a very explicit one-way data flow that we can break down into three steps there's an event such as the user clicking on a button that event gets dispatched to a block and then it will reduce the next state and omit it out as a stream so we can use it in stream builder just like we did in the previous example the first thing we'll do is install block and flutter block then import them in this file then we'll add the block provider to the root of the application the block provider itself actually extends inherited widget and it takes a block type which will define in the next step all descendants of this widget will be able to access the state where the data contained inside this block now the next thing we need to do is define the actions or the events that the user can dispatch to the block we just have one single event with no data payload we'll define that as the counter event enum with one value of increment from there we define the counter block class and it extends block which is provided by the library and we provide it with our counter event you know that we just created now the job of the block is to define the initial state this can be your own class but in our case it's just an integer that starts at 0 the next thing we do is define a reducer function called map event to state it has the current state as its first argument and the event as its second argument if you've ever worked with redux or ng rx this should look very familiar and you'll know the next step is to define a switch statement that will look at the event itself and then determine how to reduce the next state based on that event so to increment a counter we take the current state and add 1 to it and now we're ready to build out the actual home page UI widget so this will just be a stateless widget and inside its build method it can access the counter block which it does by calling block provider of contexts along with our counter block type and that should feel very natural to a flutter developer because you do the same thing for media queries and themes and things like that at this point we want to rebuild the UI when the state of the block changes we can do that with a block builder the block builder is just like a stream builder but instead of a stream it takes the block as an argument then we can access the current state inside of this function which in our case is just the integer of the counter when it comes to changing the state we don't actually mutate the state directly like we have in previous examples instead we dispatch an action to the block and I really like this approach because it separates all of our business logic from the widget which is now only concerned with rendering the UI and dispatching actions so it obviously took a little more code to get to this point but the block pattern is a solid state management solution that can pay off in the long run now I don't know if you've been keeping count but I promise you ten different state management solutions so far we've only covered five but there are five more that you should definitely know about before making any big decisions the godfather of all the state management stuff is redux which has been the de facto state management library from the react world but is also available on flutter it follows a lot of the same concepts that we just looked at in the block pattern but usually you have a single store provider for the entire app and then you connect that store to different widgets where it's needed if you're brand new to state management I would probably recommend going straight to block but if you're already experienced with redux this is definitely something you'd want to check out there's another library that recently became available in flutter that also comes from the react world mob X a poll is a lot of the same principles as redux and block but provides some extra abstractions that I think make the process a little more developer-friendly and one thing that's cool is that it has a code gen package that you can use to eliminate a lot of the boilerplate code that can be very useful if you want to apply these powerful state management patterns but have a small team or maybe you're just prototyping out some ideas quickly now mob X read X and block are all state management libraries that I would consider a pretty heavy weight that require a lot of explicit code if you just want to change some data and pass it around the widget tree then you should check out scoped model this is the state management approach that they described in the official documentation and like a lot of the other things we've looked at it uses an inherited widget to pass state around the tree but in this version you don't have to write your own reducer functions or actions or any other boilerplate code basically you just define your data and your mutations inside of a model then you scope that model somewhere in the widget tree and then you have a builder that can rebuild the UI when that model changes so it's a relatively simple way to deal with shared state the next package on this list is one I haven't actually used yet but that looks very promising flutter hooks I have used hooks in react Jas and they definitely improve productivity and also code reusability this example from the docs has a use reducer hook and you can see that hook sets up a lot of the things that we'd have to do manually like the state and the action dispatching so that's a really nice alternative to the stateful widget or some of the other approaches that we looked at for local state the last item on this list is one you might not expect firebase but a lot of people don't realize is that firebase is already a state management system that is way more advanced than anything you're going to build it may not be a solution for every state management need but it can't handle some of the most advanced aspects of state management like user authentication persisting data to it back-end database remote config file uploads and the list goes on the firebase SDK exposes everything as streams or futures which is exactly what you want with a reactor framework like flutter I'm gonna go ahead and wrap things up there if I miss anything please let me know in the comments and if you want to support this channel and get access to even more content consider becoming a pro member at fire ship IO thanks for watching and I will talk to you soon [Music]
Info
Channel: Fireship
Views: 148,213
Rating: 4.9269943 out of 5
Keywords: app development, lesson, tutorial, flutter, flutter state, flutter state management, state management, redux, ngrx, ngxs, bloc, bloc pattern, react, firebase, firestore, app state, stateful widget, inherited widget, stream builder, ios, android, scoped model, rxdart, reactivex, reactive programming, hooks
Id: 3tm-R7ymwhc
Channel Id: undefined
Length: 14min 7sec (847 seconds)
Published: Tue Mar 12 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.