The Hard Parts of UI Development

Creating a JavaScript Virtual DOM

Will Sentance

Will Sentance

Codesmith
The Hard Parts of UI Development

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

The "Creating a JavaScript Virtual DOM" 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 explains a Virtual DOM consists of blocks of code representing each piece of view. These blocks are stored in a JavaScript array, and a function is created to accept an array of data and produce DOM elements.

Preview
Close

Transcript from the "Creating a JavaScript Virtual DOM" Lesson

[00:00:00]
>> Will Sentance: So, we are now gonna diagram through a full implementation of, albeit, a very non-edge case handling, visual virtual DOM. So non-edge case handling, it can only handle two elements. Well, we're gonna make it much more flexible very soon. We start with something minimal so that we can appreciate when we add that flexibility, why we are doing it.

[00:00:21]
But in this case, we have two elements represented in JavaScript in our code. Now in practice, those are dynamic pieces of content in that, which is kinda cool, right, that's why HTML didn't give us. It is the ability to have dynamic content described in our code. That will then evaluate to actual values, name becomes empty string here, name become, yeah, hello, empty string, once we execute create VDOM off that given state data in JavaScript, once that data changes.

[00:00:52]
How does it change? The only way users are allowed to fetch what they see is via a change of data in a handler. What's the handler? I can see it defined as handle here, once that approach, which we call a handle input. Once that has been executed and our data changes, I have a feeling that update DOM is gonna come along and rerun create VDOM with our new data parsed through, funneled into our JavaScript evaluated description in memory.

[00:01:21]
In VDOM, in global, because everything's in global for ease, of describing what's gonna show up on our C++ DOM. All this stuff would not really be necessary, people, if we just had direct access to our C++ DOM. Meaning, we didn't have to describe it first in JavaScript even to get any hope of knowing what's going on in this separate runtime, except by accessing get a set of properties whenever we wanna find out, no.

[00:01:46]
Unfortunately, it doesn't exist, so there we go, whatever. We're dealing with it by building our own. So here we go, we have our beautiful new functioning pens here. So there's our web page. There it is. I already know that, good. Can you give me feedback?
>> Phil: [LAUGH]
>> Will Sentance: And now we have a DOM in C++, a list of,
>> Will Sentance: Elements.

[00:02:15]
Take it all the way to here, I think, a list of elements. That's quite big and nice, okay? Remember our schema is we load in, first, a HTML file, and that loads into our web browser engine where the parser interprets it and fills into our DOM actual elements.

[00:02:36]
Did anyone get tired of this yet? The JavaScript engine kicks off when we hit a JavaScript script tag in our HTML, which we do, which triggers our JavaScript engine to start running. But we know that from our HTML, we already have a body element on the DOM, it describes the overall page.

[00:03:02]
Our layout and render engine has done the job of adding that element, and all future ones, in this C++ list technique and object model of the page to the document, old fashion word for app, or page, I guess. Okay, we then have our dividing line, here it is, which is JavaScript on the left, C++ on the right.

[00:03:28]
And we have in memory in JavaScript, what,
>> Will Sentance: What do we have in memory in JavaScript? Phil, what's our object in memory in JavaScript? Document. Document, that's there automatically as soon as we load JavaScript. All right, good stuff. It has a bunch of useful methods. What's the one we're using here in Line 18, Phil?

[00:04:00]
>> Phil: Create element.
>> Will Sentance: Beautiful, create element. And that is also joined by a getter-setter property body. Both know where to look when they're used because of our friend, the hidden link to where, Phil?
>> Phil: The DOM.
>> Will Sentance: To the full DOM, the full list of elements in C++, beautiful.

[00:04:29]
Exactly, that was a function, that one's a property, but both act to execute code, either getting or setting, or running some other behavior. Okay, now we get into regular JavaScript, over to you Justice. Do I ask the same people always every time? Okay, over to you John, what are we doing?

[00:04:48]
We're defining four variables, what are we defining here?
>> John: We are declaring name to empty string.
>> Will Sentance: Yep.
>> John: jsInput undefined, and virtual DOM, I guess, [INAUDIBLE].
>> Will Sentance: Yep, all unassigned, and these are gonna be filled in with objects and VDOM.
>> John: And then we are declaring a function create virtual DOM.

[00:05:11]
>> Will Sentance: Yeah, I should really have put VDOM. I'd like to see it as being above, because the flow is down through. So I think I wanna do this, I think this is right. Let me just switch these around. Remember it has no order here, right? In JavaScript, wherever I assign, it doesn't have an order here, it's just a visual representation.

[00:05:32]
None of this really is real here. [LAUGH] Let's acknowledge that. So VDOM, I think I'm gonna put above because it's where the data's gonna flow through, flow from here to here down, not literally, but just in terms of our visual representation. Then I'll put jsInput here and jsDiv here.

[00:05:55]
It's not ideal for referencing the actual elements, but it's okay. Perfect, thank you, John, keep going as you said.
>> John: And then we are declaring handle function.
>> Will Sentance: So, yeah, create VDOM.
>> John: Yeah.
>> Will Sentance: It's a function, you did it already, it's on me. Next one.
>> John: Then we are declaring handle function, and then we are declaring update DOM function.

[00:06:14]
>> Will Sentance: Then handle is a function. And then, as you say, update DOM is a function, which was what our dataToview was previously roughly called. And then we're now going to put all the code that does the job of converting our full description of what we want our element to have, is gonna be an input.

[00:06:35]
It's gonna have this value property, it's gonna have this handler. We're putting all the job of converting that generic set of information in one function called what, John?
>> John: Convert.
>> Will Sentance: Convert, exactly. There it is. And now we get to running our sort of render every 15 millisecond cycle, with our call to setInterval to set what function, John, to execute every 15 milliseconds?

[00:07:04]
Or at least, sorry, we'll get that right, be added to the callback queue every 15 milliseconds? Can't say it's gonna execute every 15 milliseconds, but we add it back into JavaScript. And that function is what?
>> John: Update DOM.
>> Will Sentance: Update DOM, and it's the whole definition of it.

[00:07:18]
And then how many milliseconds again? John, how many milliseconds every?
>> John: 15, yep.
>> Will Sentance: And so that goes to timer in the web browser, and adds an interval of 15 milliseconds executing update DOM. I really should have left this dataToview, but okay. Although it's update DOM, I guess, right, because it's, yeah, converting our data into our view.

[00:07:46]
Okay, this line is done, and we're done with it. Let's make sure we have our cool stack, I can hear it being whispered. Raise your hand if you whispered that? So I got a logic ball on, excellent, John. Fantastic, call stack and then event loop and our call back queue, there it is.

[00:08:12]
Okay, all set up done. We're getting quicker, sort of, I mean, it's getting bigger, it's taking longer but, here we go, all set up done. It's 50 milliseconds. It's passed and 50 milliseconds passes and so what function is gonna be called back, Alexa, into JavaScript at 50 milliseconds or into the callback queue?

[00:08:35]
Update DOM
>> Alexa: Update DOM, there's nothing in global.
>> Will Sentance: There's nothing on the call stack, all synchronous code is finished running, so Alexa, where's update DOM appear
>> Alexa: In the call stack?
>> Will Sentance: Yeah. Okay, and it's gonna have prints added by JavaScript and Alexa, tell me what's going to then happen in JavaScript.

[00:08:57]
>> Alexa: We invoke it.
>> Will Sentance: Yeah. Threaded execution goes inside and we create a new?
>> Alexa: Execution context.
>> Will Sentance: Execution context. I don't want to get too indulgent in it being shouted. I love it, but I don't want people to think I'm. Right, perfect. UpdateDOM.
>> Phil: [LAUGH]
>> Will Sentance: I don't want people to think I'm sort of maniacal.

[00:09:20]
There it is, updateDOM. So thread [INAUDIBLE] into it. To be fair, it does invigorate me and it also does give me a chance to think what's happening next. Now I know what's gonna happen. All right, we go into it where we are going to do our job of produce, turning our little JavaScript kind of preliminary representation of what's gonna show up, into an evaluated, actually data filled out version.

[00:09:45]
Kinda nice but everything's got a visual version in the code that is obviously not got the actual values as that's gonna change and now we're gonna get in JavaScript fully evaluated data propagated at least into the JavaScript memory version of it into the global constant VDOM. So help me out here Alexa, if you don't mind.

[00:10:06]
>> Alexa: Yes, we're reassigning VDOM to the evaluated result of invoking createVDOM.
>> Will Sentance: Okay reassigning VDOM, just again because it makes it easier to the evaluated result of calling createVDOM. Which we know is going to return out and we're not gonna go into it, well we can, it's gonna go on the cool sack, createVDOM is on the cool stack and into it we go and it's going to return out an array of two sub arrays.

[00:10:36]
Each describing a different element and that's going to be returned, you said into what global constant, Alexa?
>> Alexa: VDOM.
>> Will Sentance: VDOM, so I'm gonna draw it actually out here just to save redrawing it. And can you just help me with what that first array elements going to evaluate to, Alexa?

[00:10:52]
>> Alexa: Yes, so the first sub array will have the string input.
>> Will Sentance: String input.
>> Alexa: And then the next element will be-
>> Will Sentance: What's our value of name?
>> Alexa: Empty string.
>> Will Sentance: Empty string and then.
>> Alexa: Then a function definition.
>> Will Sentance: Yes, I handle function. I'm just gonna put it up here but it's the whole handle.

[00:11:10]
And technically it's referring to this function here in memory, but just to show it up on the code, and then our next, and there's all description, by the way, just think about that. It's gonna be an input element with no value content right now, no preview text, and a handler defined attached to it, really cool.

[00:11:26]
None of this by the way is truth. Again, these are efforts by us. Not easy. I'm not going to I, [LAUGH] I'm not gonna say it. I'm not gonna say it's too catchy. All right, next element describing associated corresponding DOM element, we hope, is what Alexa?
>> Alexa: Our first, well, our zeroth element is the stringDiv.

[00:11:48]
>> Will Sentance: Perfect.
>> Alexa: And then, what evaluates to the string hello, comma, space, exclamation point.
>> Will Sentance: Space, exclamation mark, beautiful. And we don't have a handler associated. Okay, fab. Look at that, a fully evaluated, that means turned into its real values representation of what's gonna show up on the page that was described first in lines four and five in a generic when there's real data.

[00:12:17]
Evaluate this into what will end up being the actual stateful, probably a great way to save content that shows up on the page. All right, so now we go ahead and do the conversion, which is we're gonna take this content and we're gonna run it through convert. This content, this info and run it through convert.

[00:12:36]
At the output access objects are gona go here, the output DOM elements are gonna go here. Cuz a bit tricky here but let's do, it we're inside of updateDom's execution context and let's draw it out and we are going to assign to, don't get ahead of ourselves. Getting a bit too confident.

[00:12:58]
Assigned to jsInput, the evaluated result of calling convert. Paul, can you help me out here? We're calling convert with VDOM position zero. Well, talk me through it.
>> Paul: Okay, [COUGH], so the variable jsInput is reassigned.
>> Will Sentance: Yes, beautiful.
>> Paul: The result from the Convert function.
>> Will Sentance: Fantastic and into where we go.

[00:13:26]
>> Paul: So into the Convert function the node is passed that is the VDOM 0 element which is the first sub array.
>> Will Sentance: Yes
>> Paul: And so the first thing it does is it creates a constant.
>> Will Sentance: That's memory by the way people that's our memory. I forgot to write memory but that's our local memory.

[00:13:47]
Yes exactly, you create a constant LM, which is gonna be the result of calling our DOM method, which is?
>> Paul: createElement.
>> Will Sentance: Exactly. On the document object, which we know has passed what?
>> Paul: It's passed the first-
>> Will Sentance: You're so kind, doing my pronunciation. [LAUGH] You're so kind Paul.

[00:14:13]
It's passed, there you go, I'll do it for you. It's passed what?
>> Paul: The first element of that subarray, which is input.
>> Will Sentance: Exactly.
>> Paul: The string input.
>> Will Sentance: The string input, fabulous. And that uses the link from the document object on which the createElement method is found to the overall C++ list of elements, the DOM in which is going to create what type of element, or is gonna instantiate what class in the DOM?

[00:14:47]
It's gonna be type what Paul?
>> Paul: Input.
>> Will Sentance: Input, perfect. Yeah, and we then get as its output in JavaScript, what Paul? Cuz we we need a link to that, but we can't just store a link, so we get created what in JavaScript? It's a, right, a JavaScript object that represents that.

[00:15:09]
Yes, exactly, with a hidden link to that input on the DOM, and it has all the relevant functions, in this case. Well, we're gonna NWL, now here, do you see people, we're gonna end up trying to use text content, even though that's not gonna actually do anything to our input.

[00:15:26]
Cheeky, lazy, sure. In practice, a convert function here would absolutely assess for is the element. In this case, is it linked to an input element or is it linked to a DIV or is it linked to something else? Do not try and set text content of an input element.

[00:15:43]
In order to save code and space, if it doesn't break it, we're not worried. But yeah, we do know that there's input linked object accessor is going to have on it at least value and on input as useful. Get a set of properties for editing this created input element.

[00:16:09]
Perfect, well, let's go ahead and use them. In line 19, we're gonna use textContent on that element, and it's going to allow us to set the text. Well, it's not gonna do any harm. We're going to skip over it. And instead we're gonna hit setting its value, which does show up to the user.

[00:16:29]
And we are going to set its value via the setter, elem.value. Remember elem is now our local inside this execution context, convert label. We're not calling a JS input anymore here or not yet. It's generically elem because we're inside convert before we return that out into JS input.

[00:16:50]
And here the label of v object on which the value setter is elem, and then we use that value setter to set on the DOM node the value of input to what pool? What's our value on the description, not name, sorry, I mean, it's certainly is name, but it's from the what?

[00:17:12]
Node position 1, our content-
>> Paul: Basically an empty string.
>> Will Sentance: Yeah, exactly it, please stop. Exactly, yeah, stop trying to say what I'm not. And then finally we also do this with our on input setter, and set the handler for handling input on the DOM node to what function that is in our array describing our element in full, Paul?

[00:17:45]
>> Paul: The handle function.
>> Will Sentance: The handle function, brilliant, there it is. The handle function, and that is going to show there, beautiful. God, it doesn't help having pens work as wonderful, I'm so happy. Okay, beautiful. And now, in order that we can still persist the link, after closing this execution context to that DOM element, we are going to return out that object into what global, for our ease of diagramming, Paul, into what global constant?

[00:18:21]
>> Paul: jsInput.
>> Will Sentance: jsInput. There it is. Return, haven't written return for a while, but there it is, return. And there we have in global, our accessor object to input,
>> Will Sentance: To input, there it is, to input and it has its setter getter. Properties, yay, whoa. Thank you, thank you, yeah, yeah, exactly.

[00:18:54]
No, not me to Paul, to Paul. That was really fab, Paul, thank you. Yeah, excellent. Okay, so now, do we do the next one by analogy? You bet we do. [LAUGH] I'm not sure what that voice was. Regrettable I think is all it was. Yeah, we do by analogy.

[00:19:17]
So jsDiv, Alexa, if you don't mind, just sorta give me what the object is gonna be in the associated element here. Just talk me through as much as you can and I'll just diagram fairly simply.
>> Alexa: So we're redefining jsDiv to be the result of calling convert on element one of our vDOM,

[00:19:37]
>> Will Sentance: Yep, there it is, which is?
>> Alexa: So using document createElement, we are gonna create a div node on the DOM that is unattached.
>> Will Sentance: Yeah, perfect. It is actually pretty unhelpful to me to do this without going through it line by line, but it's great. So, we're calling convert, we're parsing in vDOM position 1, as Alexa says, which is div hello.

[00:20:01]
And now our node parameter inside the convert execution context refers to the index one element describing, hopefully, the content we're gonna display on the DOM. Exactly as Alexa said. We are then going to grab its node position 0, which is, what Alexa?
>> Alexa: Div.
>> Will Sentance: Div, and we're going to pass that string to createElement to create in the DOM a, what type of element?

[00:20:28]
>> Alexa: A div.
>> Will Sentance: A div. And notice, well, we'll see that in a second. There it is, a div, perfect. Now we're gonna use the textContent setter that on the returned out inside of here as element. So I guess, we could actually show that, couldn't we? Well I guess we're gonna be-

[00:20:51]
>> Alexa: Locally stored.
>> Will Sentance: Locally stored, exactly.
>> Alexa: [INAUDIBLE] object linked to our new DOM node.
>> Will Sentance: Yeah, which we're then gonna use a textContent setter on to set the text of the, so Alexa, keep verbalizing for me.
>> Alexa: Yes, so we're gonna set the text content of that new div to be what is at index one of our node, which is the string "Hellos, !".

[00:21:19]
>> Will Sentance: Perfect, and we use the textContent accessor on the elem, which is the object that we are now, because value in on input don't do anything to a div. So we are now gonna return out that elem with its accessor into what global constant according to line 13, Alexa?

[00:21:37]
>> Alexa: jsDiv.
>> Will Sentance: jsDiv, brilliant. And so now at least we can therefore see. So what was our useful getter setter that we had on here that we just used in line 19, sorry Alexa?
>> Alexa: textContent.
>> Will Sentance: textContent, exactly. textContent, and that we then used to change the linked div element.

[00:22:10]
Perfect, neither of those are yet appended on the page, but what do we do in line 14, Alexa?
>> Alexa: We use the replaceChildren method on the body of the document object, or to the body property of the document object. And we pass in those new JavaScript objects that link to our new unattached DOM elements, and then replaceChildren will append them to the body on the DOM.

[00:22:38]
>> Will Sentance: These are all linked. Here they are, and so we now attach. We use these two accessor links and we use body's accessor link to attach these two to body as children. Funny word, but there we go. And then that is field on the body, empty string, nothing on there, and a div with hello, !.

[00:23:05]
And that is the closing out of our all in one data to view updateDOM converter, is that correct? Yes, it is, and there they are displayed on the page.

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