Filip coordinates Flutter outreach programs, writes articles and builds sample code. He does the same for Dart and AngularDart. Previously, he lead Google's developer relations program in Central and Eastern Europe. Prior to Google, Filip was an independent IT instructor. He earned his master's degree in journalism with digital media emphasis from the Masaryk University at Brno.View the profile
Matt leads Flutter's developer relations from Google’s Mountain View campus. He joined the Flutter team last year, having spent three years working on Android, Wear OS, and Google Fit. Before Google, Matt worked in a diverse range of fields, from bioinformatics to digital cinema. He holds a Ph.D. in Electrical Engineering.View the profile
About the talk
Do you over-react when you hear Streams, Observables, Redux, Flux? Don't. One of the advantages of Flutter is that it uses reactive views, which you can take to the next level by also applying reactive principles to your app’s data model. Through practical demonstration and live coding, learn patterns for crafting elegant and intuitive code and architecting maintainable apps.
Good morning, and welcome to the bill reactive apps with flutter session. My name is Matt Sullivan. And my name is for the magic and we're both Advocates on the Florida team. So let's kick off with looking at how to build reactive apps in flutter. Sutter lets you build beautiful as it gives you the ability to create fluid and customized sophisticated realize there's a few examples up here just to show you the different range and types of apps that you can build with letter. At the heart of flutters UI is a powerful reactive model.
I'm going to give you the 30 seconds summary of how it works and then we can a deep dive into things first leg in flutter. All UI components are widgets as you can see here. We have a widgets button. Secondly, you take these widgets and you compose them together to create complex you wise. So we're going to for repeatedly to what we call the widget tree and that's literally how we're building these together. Thirdly and importantly flutter manages the relationship between State and UI and it only reveals those widgets when they're State changes and it relieves you of having to do that
task. So for example here when we call set stayed on the greeting widget. It's going to automatically withdraw itself. That's great. I'm wonderful building complex apps is never easy typically have thousands of UI components but more importantly they have very complicated and potentially sophisticated State that's reacting with those UI components asynchrony at various different times in your app. The good news is that flutter provide you with all the tools necessary not only to build UI but also the handle complex data flow and state in your
app that fits in elegantly. Well with flutters reactive model for building a wise enough letters. UI patterns are well-known and well-documented. You can check him out a flutter. IO strategy for handling state not-so-well-known. So we're going to focus to talk on how to do that. So we're going to take you on a journey first thing. We're going to look at the foundations of fluttering state to show you the basis of how things work. What we're going to do. Then we're going to explore how State and would you three could be married together and thirdly we're going to look at
how you can use flutter streams to elegantly manage state in your app. These were going to do some live coding and clearly nothing is not going to wrong. But we're going to do some live coding and these examples will be relatively simple, but we want you to keep in mind how these can be scaled out to more complex Dayton larger apps and importantly the examples you'll see here have been derived from production apps built with flutter with my Google and by other party. So let's dive in and look at managing state in the simplest type we can think up which
is the incremental that which is what you get out of the box new do flutter create flutters reactive mottola straightforward for uin state, but it's a little different to how things are handled with Android and iOS. So we're going to dive in by looking at this app. I'm going to look at a common Pitfall that typically catches people out with the initially start thinking about reactor systems in general. Alright, so this is a very exciting moment for me because I'm going to break a nap on stage should i o which if you think about it, that's exactly the opposite of what you
normally want to do on stage while this in the name of learning and science. So it's okay. So if you're not familiar with this app this app, it's very exciting. I chose you a number and it lets you in, that number the important parts are there's the counter variable that is the belt that you know crates to you. I hears the witches which actually shows that number number for right now and here's the floating action button, which is this guy over here, which lets you change
that reliable much bigger app, and we wanted to put them all a little more structure to it. We would do that all fun by extracting parts of the build method into its own widget, right? So I'm going to do just that I'm going to take this out create a new widget. Call incrementer. Island temps go to pays the cold over here. So we're not done over there which means we have a problem on the problem is that we cannot actually access the counter variable from here because we're in this class while
the comes about eyeball is in this class. Many ways how to solve this problem, but I have something very special in mind. I'm just going to make the viable global Because I can you make everything Global, you know where to take to make born here. We're trying to break this app. So please don't make it right. I was Global and we're going to fix this in 2 minutes, but you know, I'll stay with us so we have we fix the squiggly lines. So let's see if this actually works now it doesn't know why is that
We can add things here to see if the comes about a boy sexually changed and we see that it is it is now at 12 by the user doesn't see why is that? Well, the reason is that we're calling set stayed in the wrong widget. We're breaking the count contract offset state, which is that you call Syd State when you are changing the state of the widget. We're not changing the state of the falling action bottom here. We're changing the state of the Wichita Bobbitt and that way but it doesn't know a
price to rebuild that Floating Action button, but that doesn't do anything without text over here. So I'm going to fix it now. So what we need to do is we need to move set state is the appropriate widget where we want to show the change or the mutation of the states. So Phillips going to move it back into the homepage widget. And thankfully we're no longer have any more Global State wonderful. So what we're going to do then is what we need to do is we need to be able to pass down a reference to that function so it can be called by his child
widget. So we're basically going to update the incremental which it we're going to pass through the function to Constructor. And then what this is basically giving is a classic call back method of being able to call the function in the parent. Would you attend that should probably just work? All right back to slots, please. All right, so there was great and it was pretty easy to fix but you can imagine that if you have a much larger app with a lot more widgets. This could be a problem. Let's imagine that you have you need stayed over here
and you had have stayed somewhere over here. And now what you need to do is if you follow that pattern that I just show you and you need to pass down the stage down The Witcher 3 and that means that all the widgets that are in the path need to know about the state even though they don't really care that breaks reuse a break separation of concerns and it also potentially makes the app rebuild much larger portion of the state or of the of the UI that you would want. You only want the lymph nodes to be rebuilt. So
I'm hopefully highlight if it's two problems here or two challenges first. How do I access state that doesn't necessarily live in the widget what I need it and second. How do I notify other widgets that they should be built? I'm going to again I'm going to score this pattern that I just showed you where the thumbs down on both accounts because while it is easy in a simple app and a big app, it gets more complicated and I think we have a better option here. Okay, so Let's look at how we can handle State and the concept of passing stayed up and down the widget tree without
having to expose it to all the Atwood just in between that don't need to use it. So flutter has out-of-the-box what is cold and inherited widget on an inherited which it does is it cold state? And it allows you to propagate that state efficiently down the widget tree and it will rebuild that would you tree when that state is that stay dismutase that say changes that sounds promising that might help us solve this. What is this going to look like? Well, basically you have an inherited widget. We put it in here and that is supposed to have in the past on
references to it. We can use the bill contacts in any of the bills methods to get an access the incidence of that state and use it directly within are witches themselves. So, what does that look like in code? So I have my really cleverly David my inherited widget which extends inherited widget and in here you can see that I have play some State perfect. How do I access that what I can to set by firstly placing my inherited widget into my tree? Can I get some State and then building the widget Reba needs it and then after that I can access it
by simply using the bill context to get in reference to that widget. And then I can access the state. That sounds promising. That's good. Well sure now I can access date anyone in the tree and keep the rest of my coat drying my tree at a coarse-grained level does rebuild my state change it so that's okay, but did you notice my state was final? That's not very helpful. If you actually one of you take your state now, it's not hard to Larry mutations inherited widget. It's a bit of boilerplate. So what we're going to do is we're going to look at the library. Model and scope model
is an external package. It's built on top of inherited widget and importantly it gives us the access. It gives them more fine-grained way of rebuilding parts of our tree and it allows us to mutate State as well. So looking at code real quick scope model equates to my inherited widget and we have what's called a descendant which gives us access to the state. I want to show it in real code to show you're working but I don't want to show it to you in the incremental. Because that's pretty simple. So Philip and I knocked up a shopping cart example and
what that has is it has three areas where you need to handle your state. We got a cart page which shows the list of items. We have a cart button which shows the number of items in the car and we have a grid of products where each product is tappable and should add something to the cart. So let's jump over to my laptop and And take a look at this. Perfect. Okay. So here we have the app, which is already running. You can see I have a group of products that at the moment is just showing a snack
bar at the bottom. We have my car button which is hard-coded to show zero and we have a car page which currently is showing empty. There is no State anywhere in here at the moment. He's real stateless widgets. This does nothing except look pretty if you consider this to be pretty where were not designers, but there you go. What we need to do first we need to do we need to Define our model. So I have created car model. It extends Muslim what it does. It is simply has a card object, which is holding our state. We have three different ways of interacting with us. We got
to get her to pull down the list of card items. We have item count which gives us the number of items in the car and strangely enough. We have an add method or function which allows us to place a product to in the car. No notice here when I mutate or change my state I'm explicitly calling notify listeners and the waistcoat model works is that whenever you have a descendant widget, they are observing your state. They are listing for changes. When are State changes? We simply called notify listeners and all of those descendant widgets will be notified that state has changed and they will
rebuild So the whole tree is not being rebuilt only those widgets that are listening to it and the things below them will be rebuilt. Perfect. So, let's see how I can use that model to inject some state to my app. So what I'm going to do is I'm simply going to place my state at the topmost level up my app for Easter begin with what I'm going to do is I am going to wrap this in a new widget and it is going to be a scope model and as we can see here scope model takes a model and a child so we can keep this up tree as a child and I can play some model and I'm going to create a new instance of
cat no car model. Okay. So now I have state existing at the top of my tree great. I need to access that state. So how do I do it? So let's go down and take a look at our button and here's our button and you can see at the moment hard-coded to show 0 so what I'm going to do is I'm going to follow the same type of pattern. I'm going to wrap this a new widget and this time I'm going to use I descended with you. I'm going to type it so it knows what type of model to look for and this doesn't take a child. It takes a builder. Which will provide me with the models. I'm going to change my
child to Builder and this is a function. I need the bill contacts because that's how I inherited widget find the the BBB or gets a reference to it. We have an optional television. I'm going to use and we can have a model great so I can I do now I should be able to Simply do model. Item count perfect. We got to do one more thing to get this to work. We got to add some products. I'm going to do the super quick here. We have our grid there. We have our individual products. And again, I'm going to follow the same pattern. I'm going to wrap this in a
descendant widget. I'm going to type it. I'm going to do that properly and then again, I'm going to change this to a builder. Make this a function take my context. and my model and so now what we can do in here is we've got all of this snack bar code which I can get rid of and I should be able to model. Ad and we have a product and okay. So this is all hot reloaded. I play stayed in there. I don't have to restart my app and we'll see if this works. There we go. So we got some stateless and stateful. I haven't changed the structure of my app. All I've done is I've learned in a few extra widgets.
And with the way that this app is built. This is work really nice play. This is nice Matt, but didn't you say that whenever you called modify listeners, you will rebuild the things below the descendants. Which means that we're now rebuilding the product squares every time you click before notify lister's notice. I sold the descendants. So we're rebuilding this button but we're also rebuilding all of these products, which is that not great. So why don't we fix that real quick? Because scope model descendants has a rebuild unchanged flag and I can set that two bowls.
And so you shouldn't see any difference here, but what's happening now is These public squares are not being rebuilt. I already implemented descended for the car page because you don't need to see me type this a third time, but it's exactly the same model. They're perfect. So, let's jump back to the slides. Thank you. Great. So what is Oculus accessing State? We can access State arbitrarily down the tree without having to mess with our intermediate widgets. Perfect. We have a reasonably elegant means of notifying
are widgets Now by our descendants observing for State change and then rebuilding when that state changes to give a thumbs down and that's because I had to a be reminded by Phillip cuz I constantly forgot every time we rehearse this to do this that we had to not rebuild that part there's a cognitive load at that point for the developers. You need to work out should this rebuild shouldn't diss rebuild what's going to happen and when you evolve your app you have this additional level of needing to worry about this, so I don't think this is great and I think we probably need to
come up with a better solution to that. Funnily enough. We're not going to look at flutter support for streams house dreams can be built to fit in with photos. You are reactive model and how they can solve this very problem. Thank you. So let's talk about stream. If you're more familiar with the term observable us they are very closely related and for the purposes of art all they are basically interchangeable. So if you think about application development streams are everywhere every user input as a stream of a
synchronous events, every interaction with an underlying system is a stream of a synchronous Advance every interaction of Esther with the outside world through network is a stream of a synchronous events and crucially if you think about it all your updates to the UI is a stream of a synchronous events. So people who are familiar with reactive acts than reactive programming in general probably know what I'm going with us, but suffice to say it makes sense to think about UI programming as managing stream of the synchronous event. The good news is. Has a really good
support for streams for it has had that for a long time. Streams have all the usual bells and whistles that you would expect. I like, you know stream fence for me and God mapping folding and so on and. Even has language level support for streams like a synchronous generator is the yield keyword or wait for So we have this concept of streams in the end. And it is used throughout the. Ecosystem. And then we have this stuff reactive extensions and reactive
programming on top of that. There's a package gold RX. Which builds the reactive extensions on top of the inherent streams. So is this really great what how that fits into flutter? Well for a has this which it's called stringbuilder, which is exactly what you think it is. It is a widget that takes a stream as an input and a builder method that will rebuild every time there's a new value of the stream. So anytime you have a stream like one of your subscribing to Firebase database you can just use stream Builder to rebuild your you are so that is already pretty cool, but
wouldn't it be even more awesome if we had some kind of architectural pattern to build a rat? Auto imagine that you have a big app and it has some widgets that take user input. So therefore they are they have streams of a synchronous events coming from the user and then you have widgets that can be anywhere else in the in The Witcher 3 that try to update Whenever there is a state change in a link those two together you need something in between and we'll call that business Logic for
now, right? So you need to stream the events from the widgets that have buttons on Imports to the business logic then the magic happens and the business logic publishes streams of data changes to witches that are interested in it and a disc and then rebuilt crucially your publishing separate streams. So the other which it could be interested in a completely different aspect of your day. Any fool just subscribe to that stream. So it won't rebuild anytime. There's any change to your model.
I will only rebuild when there is change to that specific aspect of the model. So let's have a closer. Look we have students at st. James's output. How would it look like in. Well, we would have an object that has sinks events as Imports thinks as the Applewood. It is the input of a stream you puts things into it and then you can listen to it on the other end. And then there is the stream of data is out. Right so pretty pretty simple would be have a single
product called addition to which you just shove your products into and then it would have a stream of integers gold item count which would update every time the item pounds changes of So internally at Google we call these business logic components. So that is block for short. Let's switch the computer and I'm going to implement it real quick. So this would be my computer. Yes. I have the same app. It's it doesn't change. It doesn't currently work and will need to
implement this this pattern. So I already have a card provider that uses inherited fidget so that I can access card this object from anywhere in my tree as you can see. I'm I'm creating this object here and then I'm accessing it in different parts of my app, but I'm not doing anything with it yet. So if you look at the object now or the company now, it is pretty empty. It only has underlined model. So what I'm going to do is I'm going to first implement
the sing of products the info to the streaming import right? I'm going to very quickly covered it up and then I'm going to tell you what did Duff so it's going to be a thing of product called Edition. This is that inputstream that you can access external 8 and then and then this is back by a stream controller called edition controller, which is your controller is the basic class in the Stream library in dark Library. So and that helps us, you know, listen to
the stream of things that are coming from outside. Now, how would you use it in your app? You would just go to the product squares wherever you are trying to, you know, add to the streams of events. It would just say Todd block the the thing and then we want to add to this thing and the schedule going to ask the products fight coming back. We want to also coached the output which is a stream of item count so I can just recreate a quickly do that item count as a stream of ain't
And it is backed by something. We are something that you might know a behaviorsubject behaviorsubject is coming from reactive and it is a different kind of steam controller that has memory of its latest value. So whenever you listen to it, it will immediately give you the slightest value. This is in contrast to normal stream controller thorstream wear. When you listen to it, you will have to wait until the value changes that could be, you know, sometime in the future in our case. We want to have always the latest
the the moment that we listen to stream. I know how would we use that? Well, now we get to use the stream Builder class. So we have the crockpot on here. We want to it's due to listen to changes to the item count. So I'm going to wrap it with us dreambuilder of integers. It's going to listen to the item counts stream. The insulator is going to be zero and then in in here, I can just access the Snapchat of the radar which will always be the latest value of the item count.
So here we have this now. All we need to do is to merge the streams together. So that's what I'm going to do. Just now. This is where Philip will make the magic happen behind the scenes because we've got a bunch of products coming in Bound and what we need to do is we need to listen for changes on that because we're not capturing it at the moment. We need to add those products to the pardon self So while Phillips doing now, he's getting access to the stream. He's listening to it. And then the product will be the event coming in at all we need to do at this
point then is add that product to the car crate so that where we have state-managed. The other thing we need to do is make sure that item count is always updated when products are added and all we need to do there is do what we do it in the but in the opposite direction is to add the item counts to the out-of-town stream and We're done. We're done. All right pictures lights, please. so as you could see if we were able to implement this business project component pretty quickly if it is a little more complicated but it gives you a
lot of. So first of all it is really just scream saying screams out whatever happens in the component you don't care about As a flower do I then we could add more things to this block, right so we could add a stream of total pass. So whenever the cost of the car changes you probably want to update your user to to give it that and then you have a stream of list of items which is the items that you want to always update whenever you add something to the car door remove from it, right? So that is cool. And again, these are different aspects of our model that we want to show
now. I have a problem with one part of this and that is this part where streaming the total cost as integers, which makes sense internally in the component it is, you know an American value after all but what it leads to it's cold in your views like this you have to somehow turn. Perform at the Monroe medical value to some kind of string right which is if you think about it, this is business logic. This shouldn't be in views so you can go back to your car lot and you can just change this to stream of
string that is already formatted. So whenever you want to show your tote asked you to stream the formatted one and so if you disagree use that same business logic that is inside the component now that it gives you another very cool thing and that is that if you add a new sink or new in sports design model, sorry for the component, for example, sink or float owl so users smoking change anywhere in your are they can change from us show up to are you shop now, you can pipe this change as a stream
to the total task and so internally in the block you will The the total cost string even though maybe the number to value is still the same and that means that anywhere in the app that user changes days. You don't need to think about it as as a developer. It will always update anywhere else the total cops. This would be a real pain to implement any other way. So we have this nice flow of data and events. We have widgets that are only listening to what they need to know and we're using
Google stream Builders to make that work. So let's take a look at what we have now accessing State and Phillips example was solved by using the inherited widget pattern to pass access to the block down the tree. We now have very fine updating on change because we have different aspects of our data being represented by different streams and they will those pieces those widgets subscribing to those screens with only rebuild Windows aspects of data changes. And finally, we not have the converse. We have you tasting state by pumping data our
request to mutate State into our business logic where were observing for change and then we can updated as to this business nice pattern of pushing didn't invite streams and then updating by streams, which we think is very elegant. So this is great, but you all have options setstate works fine. If you have a very shallow treating you at your app is fairly simple scope model is a fantastic way for a model which is relatively straightforward to be passed up and down and change out a tree of arbitrary depth for those of you who like the Redux pattern. There is an excellent Redux implementation
built by the community the Redux package to Dart and flutter Redux 444 flutter, which will give you that pattern and you can use that as well. But if there's one thing that we'd like you to take away from this it's that What is widgets in combination with streams gives you a very reactive way to know they handle uui, but handle the flow of data through your app and handle the updating of your UI when that data changes. So we highly recommend you go and check out dark streams and the DRX tarte package as an option for
building state in your ass would love to hear from you. Please go to the site and give you some feedback. All of the code you seen today is in Phillips GitHub account. I did some Puerto Crest honestly didn't read everything and not only do we show you the code. We showed what we have a Redux implementation and a couple of others there as well for you to check out. I want to give a shout out to the cookbook that the community have been working on this wonderful patterns in there from everything from which creation to network at to Jason the great place to go and there were two other
talks that have happened prior to this fortunately. We have a time machine called YouTube so you can go back in. Time and if you want to learn about building beautiful, you eyes are building on Santa and I would recommend you check those out. Those are good talks, and I would like to say thank you for your time. Thank you.
Buy this talk
Access to all the recordings of the event
Buy this video
With ConferenceCast.tv, you get access to our library of the world's best conference talks.