Moving from setState to Riverpod in Flutter Part 1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome to cheetah coding so i created a few videos about state management solutions in my channel already i talked about packages like block get x and provider now i want to add a fourth option for you and that is called a river pod so river pod is a pretty new state management option for you and it was created by the same guy that created the provider package so if you go to the website here this video will tell you about the guy that made the provider package his name is remy i would advise you to watch this video it tells you more about why he created the river pod package and why it's better than using provider so here in the get started it tells you a few different ways that you can actually use this package so you can use it with hooks with flutter only or with dart only so for this video i'm going to use it with only flutter here so i'm going to use the flutter river pod package the flutter river pod package is already put into this app here so i added it here and i'm using the no safety version of it here okay so if you saw my video on provider 5 that i did recently then this layout should look pretty familiar to you this is the same layout that i did for that video so i can put in a name here a city and add it here add more here and then delete here go to the list and you can see it here too okay so the state is in this user list widget here which is also here too okay so that is the user list dot dart file here and right now i'm just using the default state so in my home screen we have a cheetah input two of these and we have cheetah buttons here so i created these widgets here so we just pass in the text one pressed and the label text and the unsaved function okay so back to the home screen when we press the add button i'm calling this add user function and passing the user from the form and we're setting the state here and updating the local user list here and then we're passing this list to the user list widget here with this button so when we go here we're passing the user list and we're passing the button to delete the user deleting the user is up here too so you can see set state remove where the user name is equal to the username and the list here okay so i hope that makes sense so i assume if you have heard of riverpod then you at least know how to use setstate in your app so now i'm going to convert this date to riverpod so in this api file here i created two functions that kind of mock a api response that you might get so it's just a feature with a delay here of five seconds and then i get the name here so this could be any return object in your api and then i have a stream here which could be a firebase stream for example it just creates a stream that updates every one second and it adds the session time to it so it's just a session time counter 0 1 2 3 4 etc and then it returns that stream here okay so i'm assuming that you know how to use features and streams streams can be a bit confusing at first but they're pretty easy once you get used to them so the first thing i want to do is i want to tell our app that we are going to be using riverpod so to do that we need to go to the main.dart and the first thing to do is to wrap our app in a provider scope widget so this tells the app that this widget is in the scope of all the providers that we want to use so doing that is pretty simple we can go down here and now i want to wrap this with a provider scope and then the child will be my app oops like so that's it pretty straightforward so one difference between riverpod and provider is that you don't define your providers at the top level of your app now i will show you how to actually create your providers i'm going to create a new folder and i'm going to call it controller and you'll see why i'm calling it that soon in any controller i'm going to create a new file i'm going to call this providers you can kind of define your providers wherever you want to for this app i'm going to define them all in the same place um you don't always want to do that sometimes you want to define your provider only where you use it that depends on where you're going to use it but just to keep things simple i'm going to define them all in a single file so first i will create a provider for this name here so down here i will say final channel provider or let's say channel name provider equals so you normally define your provider like this you don't actually give it a type so we say equals provider so you import the provider class here and then you define the type here so it's a type string because it'll just be a string here so string and then you create the function inside that defines what the actual data is that is being returned first i'm going to play underscore here okay and then i'm going to return this name here so and then first let's actually put that missing and then this will be cheetah coding let me put that here so this is the bare level version of a provider that you can use in your app so you would want to define it this way with just the provider class if this is a static or unchanging value okay so this channel name provider will never change so while we are here i will create a few other providers so now i want to create a future provider so a future provider is a provider that expects a future value so we can go down here and i will say final and this one i will actually use it to get the profile username here so this would represent an api call that you would have in your app okay so i will call it final profile i guess profile name provider equals future provider so provider is the base level class and then we have also feature provider underscore return that function so get profile user name and that's it so you can see a common pattern here the only difference between this and this is that this is expecting a future and we should also probably put the type of value here so it's a string so we can put string type here you can see if you try to use a normal provider you will get a error so it expects a feature here okay and i should probably talk about this underscore here so i'm not getting this value but this value is a reference to the actual provider itself so you can call it ref i see a lot it's a provider reference but for now i'm not going to use a reference to it so i'm just going to keep it as a underscore here so we have the standard provider the future provider and now i want to create a stream provider for my stream api call here okay so final then i will call it session time provider equals and then we have a stream provider okay and then for the api here this call is an ant so we could put a ant type here underscore because i don't care about the reference and then i just return the session time i think it's get session time yeah so that's all i want to do for the provider file for now so now i want to replace the cheetah coding with the provider here so this provider doesn't really represent state it represents kind of like a global constant back to the home screen and the first thing i want to do is i want to import our providers from our providers.dart file here so instead of cheated coding we can use our context to get the value of our providers i want to say context dot read but we need to import the river pod package so let's go back to here and i want to copy this and put it into here and now context.read and now we can say channel name provider okay so we imported channel name provider i'm not sure why this is here uh i put extra space here so let's rename there we go okay so we imported our entire provider file here all we did was replace the cheetah coding string with context.read channel name provider so let's restart and you can see that we have the same result here so to test that let's go to our provider and i will change this to cheetah test and let's restart and now you can see we have cheated test here so that's proof that we are using our provider so change this back back to home so that's a very very simple way to use provider just to store some global string that you want to use in different parts of your app so now let's say i want to replace the river pod demo string here with our profile username so let's go back to the home screen and here's the part where things get a little bit more complex now i want to listen for that value when it changes so riverpod has a few handy ways to do this my personal favorite is to use a sync value with the consumer widget so up here in our title we have riverpod demo now to wrap our text and a consumer widget so consumer if you have used the provider package before then you are familiar with the concept of a consumer the concept is pretty much the same thing in riverpod too but this consumer has a few extra things to it so let's say consumer and then we have builder child and key so the child so we have builder child and key so builder we will use for our text and the builder takes in a few different parameters here so first is the context similar to provider and then we have a watch perimeter here okay so watch we'll call it and then we have the child the child i don't really use a lot but it's there if you need it and then we return our text widget like so parentheses here so as of right now this really doesn't do anything different we can restart and nothing has changed so now i want to watch our future and do something when it returns so let's get rid of the arrow function and we're going to do return text here and think like this and so with our watch i want to create a new variable to watch our profile name so up here i want to create a new variable of type async value so this is a class that i use a lot with riverpod because well you'll see why in a second but basic value of type string because the profile name is a string and i will call it name and then we use our watch function so this watch here is a function so watch and then we wrap our profile name provider with that so we can say profile name provider so i hope this makes sense so far we just have our consumer which builds our text widget as before and then we watch our profile name provider and assign it to a new type called async value so a sync value helps you manipulate asynchronous data this is a really really useful class in riverpod so what you can do with this is once you assign this to a sync value type here you can say name dot so the sync value has a few different fields here you can get the data directly here when it finishes or you can do something i like to do which is called win so when gives you the option to create a loading widget so before the data is returned you can assign a loading widget here and you can also assign a error widget here too so each of these expects a widget okay so for the data you get back that data field so let's just call it name here and then you decide what to show with that name string here okay and for that i'm just going to show our text here so copy and get rid of this and then return the text here for the loading i want to put a text here too so i'm going to paste this here i want to say loading dot dot dot and for the error this expects two things here so you get the error itself which i'll name e and then it has a stack trace so you could say stack trace here remember these all expect a widget so i will put text error okay and we're getting this area here because we're not actually returning anything so let's return this and like this and these are functions so this should be a function here so that's a bit of boilerplate with the win code but i think it's pretty useful because you can define your loading widget and your error widget all in the same place here so if you don't want to actually define your loading widget and your error you could just say return name dot data or you could say return text name dot data dot value like so and then we're using no safety so okay we want to show loading and an error here so let's go back to before so let's restart and see how this looks you can see loading and after five seconds you see river pod demo that's because i forgot to add the name in here so let's put the name right here let's restart and you see julian curry so i hope this makes sense and i hope you see why this is very powerful so now let's create some actual state so the first thing i want to do is i want to go to the controller folder and i want to create a new controller so this will be a user list and then i'll just call it user list dot dart and this file will actually have our state for our list here so creating state in riverpod is a bit different than flutter or sorry a bit different than provider so in provider you have your change notifier with your state and your provider would be the change notifier provider i think it's called riverpod does have that but they actually encourage you to use the state notifier instead so i will show you the difference here so first i want to create a new class i will call this user list controller and then i want to extend something called a state notifier so instead of a change notifier in provider we will use the state notifier in riverpod and then you tell it the actual type that you want to store so this will be a list of users and let's import our user model so the main difference between this and the change notifier is that the state notifier is used for one type of state so as you can see here we told it that this is a list of users so that's all you can store in this is the list of users that's it with a change notifier you could put whatever types you want inside of it you can store like 50 different variables inside of it if you want to i kind of like the way that river pi does it because it kind of forces you to think more carefully about what you store and state and where you put things at in your state hierarchy so for the user list controller you get an error here it expects a super constructor okay so let's just do that we pass in the state here by default and then we set that state here so if you want to know more about state notifier you can go into here and you can look at all this wonderful code here but the main thing to realize is that it has a single piece of state which is a single object of whatever type you want it to be this could be a string or whatever you want okay so now we will create the actual control functions to manipulate the state so first i want to add a user so void add user and then i want to pass in the user object so user so the same concept with the pareto package applies here you don't want to manipulate the state directly so what i like to do is i like to assign the new state to the old state okay so i want to say state equals then i will put brackets here state so this would be all the current state plus the new user at the end of the list here okay and that's it so i'm taking the new user and i'm appending it to the end of the current state list and down here i want to say void we can get rid of the void i guess here so i'm going to say delete user and then i want to pass in the user object you can pass in whatever you want to here you can pass in the index you can pass in the name but i'll pass in the entire user object here and then i would say state equals state dot where so i want to define where we want to remove the state i will say underscore user because this will represent each user in our list and then i want to say where the user dot name i could define like an id in the user like a unique id but for this video i'll just say name not equals not equal to user this user dot name okay and then this has to be a list right now this is just a iterable so let's say dot two list so we're saying that the new state equals the current state minus the user that fits this boolean value here it could be more than one too but where the name that we pass in is equal to the name in the list as we go through it if those are the same then we delete that user and then we create the new list and assign it back to the state okay not too complicated pretty simple stuff here that's all i want to do for the user list controller let's go back to the home screen now i want to wrap this in a consumer i want to say consumer and then for the builder we have our context watch and child if you don't want to use the child to you can just put underscore here then i want to return the gta button but actually let's just use the normal function here and return this turn brackets so now we have access to watch the state so up here in our consumer the watch was for our actual provider itself not for any controller or state notifier now down here we want to access the actual controller class which is this but we don't have an actual provider for this yet so let's go to the providers.dart and i want to create one more provider and this provider actually represents state so down here i want to say final user list provider equals and then we have a new provider type called state notifier provider so state notifier state notifier provider and then we can tell it what type here to we can say user list controller so i want to return the user list controller here so underscore then return user list controller we pass in the state but we don't actually have to do this we can say get rid of this here and we can just pass in a empty array so this empty array will represent the initial user list state so save and back to the provider and now we can just not pass anything in here do this we just have a user list controller okay so this expects a state notifier if you try to return something else you'll get an error like test you see so okay so that's all we want to do for the state notifier here so let's go back to the home screen and now i want to get that provider and our consumer here so doing this is a little bit different so let's go up here and i'm going to say final user list controller controller equals and then we can say context dot read and then i want to say user list provider okay you can see we have an error here right so these errors can be a little bit confusing but basically it's saying that the types don't match so the difference here between how we did it before is that here since we're sending it to a state notifier this provider has a state notifier built into it so you can say dot notifier okay so this says obtains the state notifier associated with this state notifier provider okay and this is important too it doesn't listen to it so that's what we want here for this button okay so all this might seem a bit confusing you just need to get used to the the procedure of doing this if you want to read a notifier you would use read don't use watch use read so now i want to use the controller to add a new user now we're using this local function but now we can get rid of it so let's get rid of the add user here and delete user so no more local state so we can get rid of the user list here and now down here i can say controller dot add user because that's part of our state notifier here okay so we don't have our user list anymore so down here we were passing that state that local state to our user list screen and our user list down here we can get rid of actually before i do that let's change the delete user too so we can get rid of these here so i'll get rid of the delete user too because we'll change that here in a second so let's get rid of these and this and now we can remove this and this which means that we can change this entire thing to a stateless widget let's go state let's switch it like so state lists widget okay and we can get rid of these here and we can get rid of all this here too so that's the main goal is to make it so we don't have to pass all the state around and all these functions around here okay so down here in our user list remember this is the list here and on the next screen too so instead of the users being passed into this widget we want to consume the user list from our state notifier so like we did before since we're using the users in most of this file here i'll just wrap the entire list view in a consumer so consumer and then i'll say context watch and child and then brackets here return okay and since we're using the user list in most of this file i want to wrap this entire list view in the consumer so we'll say consumer we have our context watch and child here and then we can do brackets return then down here there we go okay we can get rid of this now and i will put the watch function above the return statement here so i can say final user let's call it user list equals watch and then we will watch our user list provider so we'll say user list provider and then we'll replace that down here so we can say user list user list user list okay and now for the on delete i showed you how to access the controller and the home widget so let's go down here and user list controller controller equals same thing before say context dot read and then we will use our user list provider dot so that gives us our controller here and then we can say controller dot delete user and then for the user here we want to pass in the user list here okay and that's it so you can see how this is a lot more clean than what we had before we're not passing around a bunch of variables to different widgets you can imagine how effective this would be on a much larger app with maybe 50 different screens that need to access the same variables okay so let's see if this all works correctly let's restart see loading here and then let's put in some names here and add list green you can see it's here let's uh delete this one list so a lot less code a lot more structured code we have all of our state in this one file here you can add more state if you want to the the concept of creating the providers like this is very useful because you can actually put these wherever you want to these aren't defined in your top tree structure so they're not actually related to your to your widget tree itself so you can have the same provider types defined so one thing i want to do too is i want to show you when the widgets are being updated so let's go to the home widget uh let's go up here and i want to print home rebuilding and copy this and put this in the user list user list rebuilding okay so let's restart so you can see when the app first loads we have home building and user list building um let's add a new user see what happens so you can see that the home list was not rebuilt and the user list was not rebuilt if you were using the original code with set state then every time you add a new user then the entire home screen was rebuilt including the widget itself so let's delete a user same thing you can see that it's not rebuilt so using state management is a very very good thing for performance you don't want to rebuild the entire list view when you update one thing on the screen so this is a very very useful uh library for that so one last thing i want to go over is i want to go over the stream here so i didn't actually implement this yet so get session time and the session time provider so i'm going to actually add a new text widget in the app bar up here so back to the home screen up here in the app bar i will add a let's do it down here i will say leading and then for the leading i will create a centered so this will be centered child and then we'll have a text and the text will actually just be let's just have it be a zero for now uh let's restart see how it looks let's add some styling to this let's do style font style or font size sorry text style and font size let's make it 22 i guess that looks good you could wrap the center widget in consumer but it doesn't really make sense so let's wrap this in a consumer builder context watch and underscore let's return the text let's actually do this return that looks okay and now i want to watch the actual session time provider so up here i will say async i use that sync value a lot int and then i will say time equals watch import our session time provider and that's it for the async value and now we can say return time dot when you also say wind data too so when data and you could just return the text here but i like using when a lot so we'll say text pass in the time or let's say value value get rid of this okay for the loading i just want something to show you that it's loading but not a lot of text here so i'm gonna put a text and just say question mark okay and for the error doesn't really matter but text error and this should be e and a stack trace put trace instead of 0 i want to pass in the actual into value so value dot to string to string okay so when the app first loads this will go up by one two three four five we're watching that value to make sure that it increments here okay so we start question mark 0 1 2 3 4 5. so you can see this will go up forever until we tell it to stop so i think i want to stop for the video now um this is enough for riverpod i think i will create a part 2 because there's still more that i want to go over real quick just to kind of go over what i did here i created a normal provider which is just a way to create kind of like a global variable here or a global object if you want to and then i created a feature provider which allows you to show a widget when a provider when a feature finishes i created a stream provider which lets you use a stream as the actual object and then i created the state notifier provider which actually represents actual state in your app so the user list controller controls the state of our user list and if you want to create more pieces of state you would go down here and you can create like a um maybe in your app you have a shopping cart so you create like a shopping cart that dart and then you have a shopping cart shopping cart controller extends change notifier etc and then you have a shopping cart model here so you would use the shopping cart model for your super here like this i will probably create a part two where i go over things like modifiers and actually nesting different providers that was kind of a pain to do in the provider package but it's a lot easier to do in the river pod package so yeah stay tuned for the next video and happy coding bye
Info
Channel: The Flutter Factory
Views: 5,963
Rating: undefined out of 5
Keywords: cross-platform app tutorials, cheetah coding, riverpod, how to manage state in flutter, streamProvider, futureprovider, flutter provider alternatives, statenotifierprovider
Id: nKv7Rz21vHo
Channel Id: undefined
Length: 35min 59sec (2159 seconds)
Published: Tue Apr 20 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.