The Hard Parts of UI Development

Automatic Updates with Hooks

Will Sentance

Will Sentance

The Hard Parts of UI Development

Check out a free preview of the full The Hard Parts of UI Development course

The "Automatic Updates with Hooks" Lesson is part of the full, The Hard Parts of UI Development course featured in this preview video. Here's what you'd learn in this lesson:

Will introduces a hook, which is a function added to the application to tap into and modify the behavior of an existing system or component. Hooks are commonly used in frameworks and libraries to provide extensibility and customization options.


Transcript from the "Automatic Updates with Hooks" Lesson

>> So now, what have we changed? Well, we're still not running updateDOM on a loop anymore with setInterval. Now we're only running updateDOM when data changes. How do we do that? When our data changes and we want to update the value of name to Li, look inside our handle.

We are going to run a function we created called updateData. This is a more generic function now than it was before, to which we can pass name as the key that is gonna go and update the key name in our data object. And then, it's gonna assign to that the value of Li in our data object.

You can see it's doing that inside of updateData where it's saying gotoData. Use the square bracket notation to access the label which has been passed in as a string name and set names value to, which was based on the getter, Li, in our DOM element, and then put Li into our JavaScript store.

And then, run updateDom. Note that now we have in our creating vDOM. is how we get the empty string, and then later Li to be populated in vDOM. This code updateData is code that we hook into. It is code that we hook into to handle state, to handle data persisting in our application that ensures that when data does change, we are going to rerun our updateDOM function behind the scenes and ensure that it flows through to update our page.

We can hook into this functionality that enables us to save and persist state, and when that state changes, is updated, will automatically [SOUND] run the updateDOM function that passes all of that through to the view. We can hook into that. That's all hook means. Hook into that functionality to give us access to persistent state that, when changed, well, that's just data in memory, that when changed, updates our view.

That is known as a state hook. It's very profound, people. Okay, so let's just adjust this a bit for what we did here. So now let's say we had not name directly declared, but we had instead an object of data that is going to be our state store, our store of data in our app, or at least related to this particular bit of our app, a bit of our content on our page.

And it has name is an empty string. As before, we know the first time we ran updateDOM, we would've gone in and evaluated here to be that empty string. And then here, in vDOM position 1 we would've evaluated hello and then, which will therefore have evaluated.

Do you remember we had empty string and then hello empty string here on our first pass, so to speak, of updateDOM? Yep, and then, when the user took action and typed Li, and Li showed up on this, the handle function would, instead of assigning name directly, would have.

And actually probably it's quite good that we've got a bit of a space inside of here, because we may be even able to show it, we would have run. So e would still be our object describing the event. Alexa, can you help me out here? Do you mind?

What would we be running now instead of directly updating name? What would be rerunning in inside of handle?
>> Yes, we're gonna invoke updateData.
>> Yeah, and by the way, just to be clear, we're just going back through our code and making the tweaks with this approach. Yeah, updateData.

>> And we're gonna pass in the string name as our first argument.
>> Perfect.
>> And then, as our second argument, the value on the event target, which is gonna get the value that's stored on that linked-
>> First object, we have first DOM element we created earlier.

>> Yeah, which was-
>> Which in this example was Li.
>> Li, exactly and so I guess I could show that with my green, right, initially. That was what came out of here from values call. So would have evaluated to Li, and then that is what's passed in.

Technically, that would actually have evaluated to a JavaScript string there, so we'll do it in white to show it's come into JavaScript now. And there it is, Li, and that's gonna create a new what, Alexa?
>> Execution context.
>> Execution context, exactly. Into it we go, so we're updating our data here.

We created a function that looks like all it's doing is updating our data in memory. But actually, it's low-key going to rerun updateDOM, fantastic. As long as we restrict our developers, our engineering team to never update data directly, we probably close over it, provide closure to lock it down, so it can't be accessed.

But that gets tricky in terms of the actual implementation, although not beyond. We are going to give the impression of just updating data. But really, we are also going to run our, not every 15 milliseconds now, but whenever needed on demand, but secretly, our updateDom function. But let's go into updateData, and what are our parameter argument combos here?

>> Label, which is going to be name.
>> Perfect.
>> String name.
>> String name, yeah, this isn't always easy here, name, exactly.
>> And then value, which is gonna be the string Li.
>> Perfect, string Li. And then, we're doing data. Well, tell me what's happening here.

>> Yeah, so we look at our data global variable, and it's an object, and using bracket notation, we are gonna pass in the string name and the name property there.
>> Perfect, beautiful, and assign it to?
>> The string Li.
>> Beautiful, so we're back where we were.

We then are going to run what crucial function?
>> updateDOM.
>> updateDOM. Now, at this point, it's not running every 15 milliseconds. It's actually going to run inside of, yeah, exactly, exactly. Right, exactly, inside of updateData. It's running inside of updateData after that little semicolon, updateDOM is running right there.

And then creating the new virtual DOM, it's using to populate our vDOM through the createVDOM call with, which is what, Alexa?
>> Li.
>> Li, and then, hello?
>> Li.
>> Exactly, hello Li. And so we end up where we were before, but now without running our updateDom function 60 times a second, but with no cost, no loss.

We're still updating whenever the data changes. We're still automatically propagating that through to the view, based on the data change, and based on our description. Well, not even based on the data change, based on the data and based on our description of what the view should look like in our createVDOM function call, which creates our data-specific virtual DOM array, or visual DOM array in JavaScript.

And if the data does change, we're doing that all over again, but only if the data changes. But we don't need to then think, make sure I go and actually update the data. I just get to do it automatically by hooking into this updateData function. So we can make our updateName function adn updateData function and have it work for any piece of data in our app.

We just hook into it. So they call it a hook.
>> [LAUGH]
>> [LAUGH] That sounds very, okay. We can alternatively switch to running requestAnimationFrame, rather than updateDOM directly on data change, so it never prioritizes our animations, truly optimized with respect to other priorities now. Yeah, so that would be that we could have updateDOM at the end of doing its work run itself again.

But wrap the call to updateDOM inside a requestAnimationFrame, which will then trigger updateDOM to run, but delay it to run at the back of the callback queue, such that anything else it needs to run in between, it could be rendering, it could be calls. But that's still, therefore, gonna be creating our virtual DOM x number of times per second.

Still inefficient, but at least it's not blocking other things executing. It will only do so as long as there is nothing else on the call stack or callback queue, no scroll events, nothing else that's gonna cause a user to see a block based on running updateDOM too many times.

Okay, let's have thumbs on this code. Okay, people are clear. When Ian's got a frown, I'm nervous to see, but yeah, please. Go ahead, Justice, please.
>> So we got the function handle, and then it's calling the updateData function. Are we separating that, creating a new function updateData just because it's doing its own little job there-

>> Yeah, and actually, really, I wanna make that really generic. It's not really generic enough here, is it, right? I don't think because, actually maybe it's relatively more generic. Actually, how this is implemented in practice is, when you even create the data associated with this displayed content, you're actually, well, not in practice, one way you could do it.

So yes, we are splitting that out there. Sorry to interrupt, Justice. Do you wanna continue with it?
>> I was just asking, more or less, are you splitting it out just because it's doing its own specific job?
>> Yeah.
>> Okay,
>> But notice that we could then use that updateData function for a whole slew of data in our app.

So we could then use it more generally. And that's where the notion of it being a hook. It's some code written that we can hook into that performs a task that changes the behavior, in this case, of our handle, and, I guess, of our UI component, the creation of our view and the relationship back to it, which the handle function is part of.

In practice, one other way we could implement this is, right now we are creating our data in global. We may want to create that data, and when it's created, we can actually have the creation process be storing that data, not directly, as we're doing here. Data is an object with name empty string, but actually do the assignment, do the saving of that data through a function call, as well, whose output could be the updater function.

Such that, later on, when we want to go ahead and update that data, we would use the associated updater function and know that it will be targeting exactly that data. And that is exactly how it's done in a certain popular framework known as React. John, please.
>> I had a question.

Is there a specific reason that you are using data rather than closure, or you can do the closure? I'm not sure.
>> As opposed to you doing any closure here, just because visually, it's just. So in terms of diagramming, I'm trying to, closure is my favorite concept in JavaScript, probably.

I mean, I do think it is very, very cool. It's so cool, the idea that, if you've got functions running at a later time, when a user does an action or whatever, it's being called back that, appropriately, all the data you could imagine would be there is right there in its backpack, right, and it's closed over variable environment.

I think that's really amazing. However, we're not here for that today, and therefore, minimizing complexity, I've done everything in global to remove having to do anything that would work, but via one of the most, I think, profound, but also can be tricky to add concepts out of closure.

So we are holding off it doing everything in global. We wouldn't in practice. Hooray, we managed to stop running our updateDOM 60 times a second. Although, to be fair, in our final example, we're gonna go back to it just because, I don't know, it's easier to work with.

But hooray, we are now going to wrestle with the fact that, yes, I get to create a full JavaScript representation in a one-to-one description in my createVDOM function. Good for me. No working out upon different changes from the user exactly what to update here. Just recreate the whole thing from my one-to-one description in createVDOM, data to view, one to one, beautiful in one place.

Fine, however, that semi-visual coding, the ability to then compose that and move it around comes at a cost, right? Now I'm simplistically then taking each element and recreating them in full, just as I do here with the virtual DOM, and recreating them in full on the actual DOM.

But no need! I have an archived history of the project. Well, I could do, perhaps I could archive, as it looks like I'm gonna sorta do here, of the previous data to JS representation of what's gonna be displayed. I can compare the two of them and figure out what actually changed.

And that is what we are going to do in our final code, people.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now