Handling Application State in Blazor - Carl Franklin - NDC London 2022

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
let us take a moment to reflect on what life was like when it was but you know before the spa before the single page application when we had things like MVC and asp.net web forms on the.net side of course you know lots and lots of ways to develop websites but in a traditional HTTP rest request response type application there is no state there's no way that you unless you want to store cookies or have some way to do it on the server side like the session object um everybody's favorite the session object in asp.net web forms uh it's sort of um you know you know it's uh putting round pegs into square holes or Square pegs and round holes or something like that the things don't fit right but with the spa it's a little bit easier if you've done any react or view or or angular even knockout um you know a single page application there's places where you can you can stuff stuff so let's talk about that in Blazer that's what I'm here to talk about the ways that you can manage state so first of all what is State what is in state to me application state is the things that are sort of transitory that are in memory that you need to access from different components that may or may not be in scope right um the canonical idea that comes to mind is filling out a form now I don't know if you've ever had this uh wonderful experience but in the states I remember I was filling out a form for the bank it may have been a credit card application or application for some Finance thing or whatever but they really want like this multiple page form filled out right and so you know I get all the easy stuff you know your name your address and your this and that and then you get to this page that's like you know um was your mortgage payment a b or c on this particular date so I'm like how the hell should I know right so I gotta get up and I gotta go to the file cabinet and I gotta pull stuff out by the time I get back oh I'm sorry you've timed out your session has expired you have to start all over again right what an infuriating experience that is right so session state or I'm sorry application state in that case will be everything that I've filled into the form up to that point so when I reload my session everything is there that I've already done and you know I've also had that experience where they did that for you and it's like whoa thank you very much but the alternative is pretty pretty nasty so I think of when I think of State I don't think of Secrets I don't think of anything that needs to go in a database I think of you know my name my address my phone number that kind of thing or just data that I have set to use in the application that I want to be able to access from different places it could be as simple as a switch like a toggle switch that I turn on in a toolbar or something like that it tells me I want to see some features or something like that right and it isn't really isn't really a view model either I mean we think of when we think of state and objects that we want to know when they've changed you know we think of view models and I notify property change I actually did a show a Blazer train show revisiting mvbm and I asked people like Steve Sanderson and Chris Sainte and um Tim Corey and a couple other people people I really respect in the business what do you think about mvvm with blazer Jeff Fritz from Microsoft was never and they're all like yeah you don't really need it you know Steve Sanderson didn't say that he said he's very diplomatic he said well we made Blazer to be sort of agnostic to whatever patterns you want to use uh we tried to make it as simple as possible so you wouldn't have to you know put stuff on top of it but if you want to go ahead yeah he's Steve Sanderson he's diplomatic he has to say that but everybody else was like you don't need mpvm you know what you need is to be able to have some properties or you know an object that has properties where they're accessible from all the different components and all the different pages in The Spa and they're taken out of the page itself so just a little recap about what Blazer is it is a single page application there is only one page even though that when you navigate to different pages you can see up here at the top the the URL changes but that's a route within the same application you're not going and getting a whole new set of HTML and replacing it in the browser right it is a spa it's a single page application but the problem is and you can see this right here and I'm sorry to use the counter you know it's there it's everybody's sick of the counter but you can see if I increment the counter and I move off the page and I go back it's it's zero again and that's because every time you go to a page or a component uh and you navigate away from that page and you come back it re initializes and any page level variables that are in there get wiped out get re reset so let me show you what that looks like and here's Blazer Train by the way um if you haven't seen this resource in your Blazer developer you really should um if I sort the videos descending the last one was episode 77 revisiting mvdm so yeah there's quite a lot of stuff in here that you can use um but if we go back to the application here and we go to the counter page you can see that this variable right there current count is just a page level variable and that's why it gets destroyed and reinitialized every time that page gets navigated to so let's we can use this as an example but of state but also add a few more things so I'm going to show you three demos here today the first one we're going to do application State using a cascading value if you don't know what that is you will soon second we're going to use a service that we can create a class and add it as a scoped service so that there's one instance per user and we're going to do that because we might need to to handle an event when the state changes because we're doing something other than refreshing the UI and the third is to take that App State and persist it to local storage so that if you're filling out a form for example and you your session times out or you come back later at a certain time you give it a timeout window your data will come back to life so let's start with the cascading value so I have a just a simple Blazer server application here and all my code and my toolbox is missing that's awesome wow how did that happen you guys find this happens occasionally like your your toolbox data goes away and then it comes back and then it goes away okay shift that's what we're gonna do I'm going to download from Blazer train actually I don't need to download it I have I have the code here so yeah I had all these uh things in my toolbar that um that I could uh just code Snippets and they're gone so we're just going to do this the easy way we're going to pull up the application app already already done so the cascading parameter type is a is a cascading value it's a um how should we call it a a component that you wrap around the entire router the entire app and then you can initialize that or you can access it in any page or other component just by adding a cascading parameter so um in my shared project here's my cascading App State now this is Blazer server but it would work just as well on Blazer web assembly right there's no there's no difference so here's a pair a pattern you might see when you want to have a component that wraps content that wraps markup you have a cascading value for this component and you have a render fragment I call it child content and it's a parameter and that child content goes inside this cascading value now on this component I've got some properties I've got a counter property and the only difference between this and a regular get a regular Setter is that when I set the value I call state has changed and state has changed is something that you call to tell Blazer that hey something needs to this page needs to be re-rendered or this component needs to be re-rendered it's actually at a component level and so anything inside the child content will be re-rendered okay message is just a string and we call state has changed again when we set the value and the same with this Boolean property enabled okay so now if I go to appraiser I can wrap my entire appraiser the router which is this is what was there beforehand in this cascading App State param component all right and now I can let's create a toolbar component which I've added to the shared folder and this has a cascading parameter not just a parameter but a cascading parameter called cascading App State and I call the name of it is App State but this basically says Okay I want an I want to have a reference to that instance and there's only one instance per user okay so here I just have some markup and I'm looking at App State enabled and I'm showing a button with that's going to be green that says enabled if it's enabled and otherwise I'm showing a button that says disabled that's going to be red now I've also got another button called update message and when I call that when I click that it calls this update message button clicked which sets App State message now I don't have to do any notify property changed or anything like that I just set the message because in the setter I'm calling status changed wherever it is message updated at the current date time uh then if we go to main layout instead of the regular about box that I have normally across the top I'm showing the toolbar right there that's the only difference there and now let's go to the main page the index page and look at that and I've also got my app State reference here so remember this is a reference to the same instance there's only one instance per user right so here's my app State and I'm I have a button to toggle enabled which basically sets it to the opposite of what it is and another one to set the message so now I can set the message in the toolbar which is always visible no matter what the page is and I have a button to change the message in the main page as well so let's check it out all right so here's my enabled toggle you can see that this button right here is changing if I update the message I can do that from the page and I can also update it from the toolbar in the toolbar no matter where I am I can update it and show it right if I go back to the home page the message should say 10 34 31. and it does now I also have this child component and just to show you that we can go down a level I created a child component also exposing App State and we're setting the message from there as well so this is a child component that's going to be on the main page now we're not displaying it but we could we certainly could we just have a we're setting the message to message updated by child component so boom there you go so now we've got a page a child component and another component up at the top the toolbar that are all accessing the state and I also had Rewritten the counter page so instead of the counter being a local variable it's App State counter and here's the the value of that such as it is I could set the counter here like six or seven I can go to another page and come back and it's still there and the code for that is just what you'd expect yeah I'm I've got another app State instance not instance but reference in there okay so this is where I would start with App State I would start with a cascading value and the the Restriction is or or the the use case is the only thing I need to do is update the UI okay if all you need to do is make sure that this component can update the UI or read the value of something right great but what if I want to act on uh you know when another component that's not me changes the state okay now you need to have an event handler and it's not that simple because let's say we Implement an event handler in this cascading App State right so we have to have a dispose method right because we have to unhook it when we're done and how do we know who mutated the state how do I know if it wasn't me right I so let's say that you want to do something like um you know write to a law or something like that in the toolbar when the state changes all right so you hook the event but what if the toolbar was the one that changed the state do you know what I'm saying so so you have to think about not getting into a quagmire with your code and so there's another way that we can do this and that's with the scope service so let's open that demo any questions on this one while I'm opening the new one no no it just re-renders the component that you're when you call state has changed it's within that component yeah so let's look at this guy we've got uh in a Services folder we've got a class called App State so app state has a message property an enabled property and a counter property and I've got private Setters on here because I want to control how these things get set I don't want to Simply have a public setter because I need to know who mutated the state if it wasn't me great I can take some action right it's just a little extra bonus that I put into this architecture so I've got a notify State changed method that takes a component base or a component so you could use this from uh inside a component or a page and then the property name and then I'm calling this invoking this event State changed if it's not if it's not no in other words if if somebody is handling it I want to invoke it um passing the source in the property so here's my event it's an action of component base and string State changed so now I have some public methods for updating those values rather than just being able to say you know message equals or enabled equals or counter equals so I have update message update enabled update counter so they're able to do the sets because it's the setter is private and then we're going to call notify State changed so we still have this toolbar right but the toolbar is going to inject the App State and before you can inject and this is an older demo so we're using the startup in configure Services you add a scoped service and a scope service is different from a Singleton in that you get one instance per user us if you add Singleton like weather forecast service you're sharing one instance with all users okay it and this is in Blazer server Blazer web assembly there's no difference because there's only one user right so we're adding App State as a scoped service we're injecting it into the toolbar we're implementing eye disposable because down in on initialized we're handling State changed with uh this guy right here app state state changed and we're in dispose we're unhooking it with minus equals but you can see right here if source is not this than somebody else mutated the state it wasn't the toolbar and then I can take I right here all I'm doing is calling state has changed but you get an event right you can do something that's non-ui related like a log or you know something else follow so that's why this is a completely different model from the cascading parameter if you're wanting to use a cascading parameter or cascading value the only thing you can really do is you know update right or whatever you can do in that setter right but do you really want to do anything in that setter well that's up to you so if a component needs to know when the state has changed then who changed it this is a good model um likewise in the index page we're doing the same thing we're injecting App State implementing disposable same code as before with a child component and instead of saying enabled equals we're saying apps they update and equal update enabled this passing this and App State enabled not App State enabled same with the message so we create a message we call App State update message passing this and the message and counter the same way right injecting the App State disposable update counter there you go and the child component the child component doesn't need to know in anything is changed because we're only setting the value but we're setting it with the update message yes 25 things magic software investigations sure yeah the question is can we see that App State again um here it is sorry about that uh yes so here it is so update message sets met the message property which has a private setter and then calls notify State changed so anybody who's hooking that event can see it okay so this should work exactly as it did before right the only difference is now we could actually in let's say toolbar put a break point here and if the say child component of the page updates it you know let me make this better if if if I update it everything gets ignored but if the page updates it now I get control now I can do something in the toolbar yep and I know that the source is the page I know you can't see that but it's application State page Pages dot index application States the name of my app questions other questions yeah so the the main benefit of the second um of this of this scope service is that you can get control and you can have an event handler in another component that's that's the main it's not really about updating the rendering um I'm doing a a I'm doing this because it has to be done anyway you know and uh so but it's not it's not about that it's really about getting control when something changes which you don't get with the cascading parameter other questions okay Let's uh try this this other one here yes yeah that's a good good question can you have more than one app State class yes of course um I I was of the mind and I still am that you know you can put everything in one state bag if you're just going to have a single App State but if you've got like a whole bunch of things that do different things you might want to break them down by task right which is sort of the Redux way of doing things in that you uh you have every every task that you want to do has a state it gets more complicated but you know you certainly have the the ability to do that if you want it's just a service you know it's just a scope service so you can have one for every different task that you want to do it's just more work because now you have to implement it where you want and not where you don't want yeah great question though all right so let's talk about persisting App State so this is that example that I was telling you about where you're filling out a form and you know you you run out of time and your session expires and you have to do the whole thing over again how horrible and it truly is so for this demo I'm using a tool that uh Chris Santi wrote and Chris is here in at NDC and he he's doing a talk or he did a talk uh he's written a lot of tools he's written a lot of great components open source components for Blazer and one of them is local storage blazered local storage right here Blazer local storage and uh it's a nuget package there's you just Google it you'll find it and what I'm doing with this is I'm using it to store to serialize the state and to store it um in local storage now local storage you get five megabytes per URL per user right so that's all you get so it's not like you're gonna stuff you know thousand records in there you know that's not what it's for right you get five megabytes so here I have a little bit of a different architecture I still have a cascading value but this time the cascading value has an app State Property so I have both in one and the reason I have both in one is I don't want to serialize the cascading App State provider I just want to serialize App State now I wrote this in net 5 when uh the the state of system text Json was such that you couldn't serialize uh properties with private setters and you could do it with newtonsoft Json so this is and you can still do Newton soft Json so this is what you have to do you have a private Setter on a property you have to set it as a Json property which means it will be serialized even though it has a private setter so that's why I'm using Newton soft Json but check this out so app state has the message the enabled the counter but it also has a time to live in seconds so this is our timeout for storing the App State in local storage and I just have it set to 60 seconds to demonstrate to be able to demonstrate up here that if I wait 60 seconds which is easy to do on stage during a demo it will no longer be available but for in the real world you're probably going to want that to live for what a day two days two hours I don't know that's up to you uh and then a date time for last access because I want to compare that obviously to the time to live in seconds how much time has elapsed since I last accessed this now the rest of this update message update enabled update counter and notify State it's all the same as in the service that we had so you'll notice that we're not injecting it as a service because it is uh hanging off of the cascading App State provider right here's my local storage service and you can see here that I'm calling wait let me close this calling local storage service get item as string async Upstate Json and then I'm looking to see if it's not null and again this is this is older code so it's not as efficient as it could be today I'm deserializing the object and then I'm looking at last accessed checking the date time and if it is within the window I'm setting App State to that object otherwise I'm instantiating a new app state now I have a save changes that's synchronous and one that's asynchronous we're setting last accessed is now serializing the object and then storing that in local storage and just in case you need a link to something that shows you how much local storage you have and guess what it's five megabytes here's the link uh again the appraiser we put the cascading App State provider around it and you know our our toolbar looks very much the same right except that when state has changed we're going to save it right here in the toolbar this is the only place we're going to save it even though we're accessing it in the index page we're not going to save it there right we're just going to invoke status changed so let's do this demo value cannot be no yes is there a reason why why I wouldn't want to have the save in of the state itself oh yeah because you can't you can't deserialize yourself and replace yourself that's why yeah yeah um maybe I already in what's occurring to me here is I get this error cannot be no is that it might be this guy right here is something that's already living on my in my application here so let's just change that one more time that's awesome that's so awesome all right let's see here I can figure this out just run it one more time foreign tool called debugging break point I'm going to put one right there and by the way oh yeah okay so this is actually a webassembly application that's why that's what's going on here and I might not actually get that break point because it's a webassembly application value cannot be null parameter input yeah this is awesome it's just great no I didn't need to do that because it is a parameter of um injected no we're not in the sorry um let me check I didn't think I did I don't think I had to because it is a property oh yeah I'm injecting local storage yeah that's great input input foreign builds no problem all right let's see if I can do something else here John you have a um a repo I can download that does this storage right all right let's try let's go back the Blazer train and download it again oh I know what I can do to get this show video of it working yes yes I can persisting App State so we're going to go toward the end here hi I'm Carl Franklin hey Carl Franklin how are you let's go toward the end and create it it's exactly it's okay it's within what's wrong that's 113 bytes by the way we can update the message update the message here updating the child component just like we did before now let's close the app run it again within 60 seconds and there it is this is exactly the way we left it so you're gonna have to trust me and look 90 seconds later there you go all right so there's one other thing I want to bring to your attention which is new is kind of new to me because I was never really a Redux uh person or or but there's um a tool called fluxor and I have a managing app state with fluxor which uses the flux pattern but it's all C sharp and it's all for Blazer so anybody do Redux and yeah okay and react so it's that pattern it's the same flux pattern where you have a state and you have a manager and you've got a store and then you have a dispatcher and you know there's a lot of stuff and there's a lot of steps in here but it does work and it is really cool and I guess the whole reason that you would use this is it the state is immutable so rather than uh rather than just changing the state from from somewhere and then getting you know knowing who changed it right like I do you replace the state and you have the the prescriptive architecture is as you said to have different State uh stores for each task that you want to perform right so whereas you know you might have one for um adding something to your shopping cart that's a completely separate State bag if you will and it's completely separate store because it only deals with those things if you want something that is shared among you know a task where different components have to know when that state changes then those guys can can handle the state in in there without fear of stepping on uh each other um I don't know I'm not convinced that this is a really good way to go it's a bit complex and you know my my colleague uh Dom wiebea from Dev expresses also feels the same that it is cool but it's a lot it's a lot of stuff there so I would start with the cascading option and if you need to get control Beyond um you know if you need to hook an event when somebody else mutates the state then you could use the uh the service the scope service if you want to persist it you can use both you can have the app State service hanging as a property off of your app State provider which you can then use to serialize and deserialize that and store it somewhere it doesn't have to be local storage either it could be you know in a database it could be in a cookie I guess if you really want to it could be in a sqlite database you know so that that is pretty much it I mean if you have any other questions I'll be happy to take them now yeah which is better indexeddb or sqlite um indexeddb has been classically the way people go but sqlite is kind of like the new hotness with blazer um I don't know does anybody else have an opinion on that I haven't used either really so with blazer anyone yeah yeah I I think if you're getting more than five megabytes of State you might want to reconsider what's going in there but I have no idea what your application is so I don't know yeah you might want to use a database on the server side instead anybody else questions I have a question how come I can't get heavy cream in London anywhere double cream yeah how come I can't get that yeah I know but the Barista is like the coffee places they're like why would you want that never all right well that's my talk you're getting out a little early thanks
Info
Channel: NDC Conferences
Views: 5,161
Rating: undefined out of 5
Keywords: Carl Franklin, .NET, Blazor, App, UI, Web, NDC, Conferences, 2022, Live, London
Id: k0URnQ01064
Channel Id: undefined
Length: 41min 44sec (2504 seconds)
Published: Mon Aug 01 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.