The Hard Parts of UI Development

Understanding UI Components

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 "Understanding UI Components" 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 the concept of a UI Component, a function that fully creates elements and the logic to bind the data and view layers. The dataToView function will include this behavior by creating the input and div elements if they do not exist, then updating their displayed values.


Transcript from the "Understanding UI Components" Lesson

>> Speaker 1: So, the data to view function is gonna have not only as we can see in line 8 and 9 there, where we convert our data to our text content based on the underlying data, whatever it is. We also based on our underlying data, going to convert that data to the buckets, the containers that are gonna have that data in on the view.

Now, we can see the input is unconditionally showing up every single time. That's not determined by posts. I mean, it is implicitly, if post is there under all conditions, display JS input. Any state of post, display JS input. Any value in post, display JS input. JS div only display, if post is not will, if post is will JS div's empty string won't display.

We are explicitly making all of our view, everything the user sees, dependent on underlying data. No hiding from that data, no hiding from our data, yes, no hiding from our data, it's the cause of everything the user can possibly see and change. Now it'd be fair, we could say, well, hold on, if we know we're not gonna change input under any condition, just put that back on the HTML directly.

It starts to become like, firstly, who knows, someone else on the team decided to actually do want to have the input field under certain conditions be removed or added or whatever it might be or focus state change on it or something like that. So, in the end, one was everything we could change, but also it's like once you start going into this mode, why not have a full description of what you wanna have displayed within this function.

Put it all there, single source of truth for anything that can be changed and or is just being displayed viewed by the user that depends on underlying data. Even if the underlying data is in all conditions or the value of post, undefined, empty string, text in it, always keep the input field there.

Now, the other change we gonna make, the handle input function is being added, no change. With this, we are going to have to rather than have our input and div, they're automatically from HTML. Essentially implicitly starting with div input as true as present and then switching them off, which now we have to reason about their change.

Instead, we're going to only create them if we want to have them displayed at that moment. So now, we're not gonna have HTML producing idea of an input, instead it's gonna be produced inside the standard of view function. Meaning there's that interesting line in line 12. I say interesting cuz it's such a strange wording.

I mean, I'm not gonna, if you think anyway. We're going to take whatever is currently on the page and then re-add it or add it or not only based on the underlying data in that moment that the data to view function is being run. So we're therefore using this replace children method on the body getter setter property on the document object that gives us a link to.

We've kind of mastered from for now, but all elements on our page are actually going to be children a sub elements of a body object that describes the overall or represents the overall page that the user can see. And what we're gonna do is have each of input div and script technically be added or input in div technically be added as sub elements as nested elements in body.

And note, whereas with HTML, we got to add them automatically to body, we didn't even say, I probably should have said at some point. They got added automatically as children of body and sub elements as nested elements of body and therefore showed up inside of that page, right there sub elements of their nested elements a body and this is body.

Then these div in input show up inside of it on the page. We did that automatically via HTML. With JavaScript we're gonna need to manually add them as sub or nested elements, which is replace children. If they're not yet on there, or there's anything on there, replace children is adding, if there's already something on there, it's switching out for the new.

Okay, so we're gonna start walking through this but Mark, do you wanna ask or do wanna have that question shared?
>> Mark: I asked if they still wanted their questions, I asked and nobody said anything.
>> Speaker 1: Okay, yeah, so we're doing thumbs. I'm so sorry. We got to do a whiteboard.

Whiteboard wipe down. Let's have thumbs, everyone's thumbs out for the big picture.
>> Speaker 1: Why has got very cool, very cool. Phil has a clarification, brilliant. Ian is a wonderful, I don't even know how to do the fractions there. You've got 25% of 75%, excellent. I'm really pleased to see it.

Paul's got some clarifications just as he's got them. Beautiful, let's start with Phil's.
>> Phil: Just a quick question on the previous example that we just diagrammed with the remove function [INAUDIBLE] remove method and then how that's updating our actual C++ DOM. Now this may be kind of inconsequential but the div that we removed, the structure of the DOM after we removed it.

Is it because we've transitioned that div node to a different part of the DOM? Or is it because we've updated a property associated with that div that indicates that this is no longer actually being rendered to the DOM?
>> Speaker 1: Wow, what a great question. We'd need to look at the actual implementation of that to see.

I would be curious, we have to look at the exact implementation, but what we'll find is that these sort of selector queries will not be searching for these elements. Would that imply the best way is to remove, move a reference to it to somewhere else, or as you say, set a flag of do not render.

My question would be, surely if it's still there, that every traversal would require skipping, essentially, it would seem unlikely that the best. But, it's interesting to think, because you'd have to imagine the designers have assessed. If I'm asking for the children of a, let's say, a set of a given DOM node, and I'm going to have elements in that, that I'm gonna need to check should I count them as relevant children.

Or are they not actually children on the tree directly on the actual displayed because they wouldn't show up, if you were to remove the children will no longer include that div. Is it more performant and is it more typical that we'd be needing to skip and it's more performant as well as skip when we count how many children there are?

Or is it more performant have it fully removed so that we're not having to re-evaluate that every time? But that's gonna be an implementation decision of a designer. I think likely, one would want to update the, they call this the tree that render tree the elements that are gonna be displayed.

I would imagine you're gonna wanna have that mirror what's being displayed and unattached DOM nodes. Partly because if we don't have a label, if we were to reassign JS div to an empty string, then this is now gonna be automatically what's called garbage collected cuz at that point it is no longer.

Accessible from either JavaScript because none of the querying will get reached to it. It's no longer on the list of elements being displayed, so all of the document as a whole searches, or can't reach it. Nor is it accessible via like trying to find the you can use what's called traversal API methods that allow you to look at sibling elements for example, look at the next element along.

You can't reach the div from those once it's not appended once it's been removed to us in all purposes, it's been removed. Except that because it still has a job to reference, a label for it with a hidden link in order this is an error it doesn't actually get deleted only when JSDF gets reassigned to let's say an empty string or undefined or whatever.

Will the C++ garbage collection remove this underlying object in full. Great, let's have another. Yeah Mark, please.
>> Mark: If input.value is automatically returned by an HTML input. Why manually set it with JavaScript? Is there something? Or, yeah, why manually set it with JavaScript? Are we leading up to something, or did I miss the point?

>> Speaker 1: [LAUGH] Are we? It was the word HTML there that threw me slightly. So you can just.
>> Mark: Input.value is automatically returned by an HTML input. Why manually set it with JavaScript? Are we leading up to something
>> Speaker 1: That word is I'm losing the word HTML input?
>> Phil: They're talking about the forms API I think that uses C++ inside the DOM to update the DOM

>> Speaker 1: To ensure that they are, [CROSSTALK] which is what we were talking about yesterday, which is I assume what they're saying, right, is when we wrote Will in here, when we wrote Ian in here, when we wrote John in here, it shows up for the user immediately. In fact, it has right here on the DOM, Will or Ian or John as a string on the DOM in C++ immediately, and the user sees it.

We don't need to funnel it through JavaScript to then re-display it. Why would we possibly do that?
>> John: Isn't he talking about the change that you made on input having in HTML versus putting it through JavaScript?
>> Alexa: Like Create Element?
>> John: Creating Elements?
>> Speaker 1: Is that always saying?

[INAUDIBLE] No, but they talked about value, they're talking about the value- [INAUDIBLE] They talk about the value gets a setter. I think that's also interesting. I think they're asking if Will is typed in here or Ian is typed in here or Alexa is typing in here. Then it shows up for the user right there and then why possibly did I go about grabbing that data?

And then redisplaying it on the DOM, it was already there Well as we said yesterday before we closed up and we did get, we dwelled on that again then if you remember someone asked the same question. It's not a truth, it's not a truth, it's a move. It's because now I am 100% sure.

I can totally not make that update. I could totally have
>> Speaker 1: I could totally have in my handler input, only updated the divs text content, because that's the only thing that needed to be updated. That was already said Will, already said Ian, already said John, already said Alexa, I already said it.

However, when you've got thousands of elements on the page, and I have to work out in every single user action which bit to update on the page, in which handler, it's not that I can't, I can. Exactly as the person in the audience is raising, our friend in the audience is raising, that I absolutely can't, I could just leave it as it was.

But now I have to up my reasoning. I have to work out which bit under which condition under which behavior by the user do I need to update here in the DOM? Do I need to update the div or only the input or only the input or only the div?

I don't wanna think about it. Instead, I only want to have some underlying data and then one single function that always updates all possible dependent content, even if actually nothing was needed to be updated. Even if actually nothing changed. I would also say to our friend in the audience, why did I initially set text context to an empty string?

Why did I initially set a value of the input to an empty string? That was empty anyway, and these were default empty. I did it because I don't want to have anything displayed that is not a direct consequence of a piece of data in JavaScript, in this case, post.

And why? For the simple, slash not, reasoning freedom it gives me. That now I know that everything the user sees can be directly tracked back to a piece of data. And where's it determined from? One function, one function that can handle any possible piece of data. Any possible state of the world in this case a state of application, not from some handler, which actually we've got back here.

Here, we're back to our handler handle input, being a source of truth being a place that determines what the user sees. Now we're determining whether a JSDF is there or not from a handler. Not from our JavaScript data. In that case, we are in a tough place. We want one place, one function that can funnel all of our action through, all of our change to the user's view through.

If the question was instead, why are we in our code? We're about to do now? Why are we also creating our input there? When that doesn't change, under no circumstances is there not an input field in this code? Well, as I say, firstly, someone else on our team could go, actually, you know what?

I think if the user types will twice, we're gonna make input disappear. They need to really learn to stop trying to type. I don't know. But then that means input could be, it's part of the view that can be changed by the user. In theory, we might want to enable it to be.

So put it all anything that could possibly be changed by the user, put it all in one function that would depend on data. In this case, the dependence is post has any state, any value, and still input will be created. But it's still post has a value and input is created.

It's a mental framework for thinking about how to structure this relationship between data and view you know what it's gonna be? It's gonna be everything the user sees must be associated with some underlying modeled out data and then the user when they take action gets to submit changes to that.

We write the code to do so, the view gets updated every single time based on just that data, nothing else. No handler, randomly changing the view, meaning we know exactly when the change is happening inside that data to view function. And that's where we're going to come to now.

That's what I'm doing now. Yeah we've had some more thumbs here please Ian, go ahead.
>> Ian: Couple questions, first one is for document body replace children on the slide that-
>> Speaker 1: Yeah we're about to go to that one. So I'll probably through questions too after we've actually diagrammed this slide.

>> Phil: Okay one quick clarification from chat on this They said there's a notion between controlled or uncontrolled inputs, especially in react where controlled is where you're kind of having JavaScript take over everything, whereas in uncontrolled is essentially the event handler Does its work here?
>> Speaker 1: Yeah.
>> Phil: Changes it fires

>> Speaker 1: Exactly, and it does the work directly here and the user sees. Or are we going to kind of take control and update what the user sees from our data? And that's where, as we go through UI hard parts, remember that a framework in full, is gonna go, is gonna be full of smart, intelligent engineers in different teams, saying, excuse me, in this edge case, could you just your library to be able to give us the chance to sometimes directly overwrite what the user did and see their typing as a submission that we then replace with the actual data from JavaScript?

And sometimes let them do it directly and let us have control over whether we do that. And those are the evolutions of libraries. One of the reasons why, as a library becomes like React, something used by like tens of thousands of large engineering teams, they can start to become.

I mean, they're just fascinating quite heavy lifts, as engineering teams, to maintain them, because they are handling different edge cases for every possible scenario, for scale teams, meaning implementation details like this, or not even implementation details like this. Sorry, not even edge cases, control being given to the developer to determine, do they want to have the library behave one way or a different way becomes.

And that's where libraries can become bloated, but by nature. They kinda have to be because they're dealing with so many different versions of engineering teams with different goals. Alexa, go ahead. Ian, did you get your, do you want to just, I know you were just about to start a question.

It's about replace children, we'll hold it till after.
>> Ian: Yeah, the other question was about, like, DOM Node Purgatory.
>> Speaker 1: Yes [LAUGH].
>> Ian: Can they.
>> Speaker 1: Ian's going to be in charge of writing the catchy names for these things.
>> Ian: [LAUGH] Do you know off the top of your head if they're query-able, searchable, reference-able, or is the only way you can access them by the access or object you have in JS?

>> Speaker 1: Correct, correct. Yes, Alexa.
>> Alexa: It was on the note of the inputs, even in our case here, is that
>> Speaker 1: Right.
>> Alexa: If you wanted to make the the choice of not storing the input value in our JavaScript until the user presses the Enter key, or clicks a submit button, or something?

>> Speaker 1: Perfect. That would be a perfect case where, why do we need to have underlying data associated? And that's right, people, where, remember, we're dealing here with minimizing our complexity with our diagrams here. And in reality, there are. And in this case here, we can just change our handler and what it does.

But once you have a framework, any of the things we're doing here will be written up as functions that are built by the framework to run. And suddenly you don't have that freedom. And that's where the pull request goes into the GitHub repo of the open source library and says, hey, excuse me, can you make this function take another argument that determines whether or not we're going to actually update the underlying data or let this happen directly and not associate any data in JavaScript with it, until maybe the user presses Enter, for example, yeah.

And that's a library design decision. And the point of all these libraries, and that's why when I say one-way data binding is standard, sure, slash three or four other different ways it can be implemented in every one of those libraries, because libraries end up having one defining way of doing something that the creators see as being the sort of, not best practice, even, per se, but the paradigmatic standard within a library.

That's the paradigm of one-way data. It's a paradigm of, I don't know, unidirectional data flow or a given library, but you can also have all the other ways somewhat possible within these libraries because they kind of want to be the best of everything for everybody once they get big enough.

Because it's like any app, right? The notion of a Photoshop has to handle all the legacy user needs, has probably a vision originally, but in the end bolts on 400 other features, and the coherence starts to go. But I wouldn't blame them for that. That's the nature of serving millions of different users, each with their own historic priorities.

>> Paul: In the new slide.
>> Speaker 1: Yeah, yeah, okay. We're going to walk through this code.
>> Paul: And it may be answered by your walkthrough, but
>> Speaker 1: Yeah, good to [CROSSTALK]
>> Paul: And I'm getting in the weeds. The jsDiv, if it will be set to a string or an empty string, and then you do jsDiv.textcontent, there is no .text content on an empty string, is there?

>> Phil: Isn't a string an object? You can just assign any property to it?
>> Speaker 1: Mm-hmm.
>> Phil: Is it too primitive?
>> Speaker 1: [CROSSTALK] I think, let's walk through it. Let's see how it plays out. Let's see how it plays out. Let's see how it plays out, and that could be a problem with this, but let's see how it plays out, because I think it is handle-able with the code as it's implemented.

But again, let's see how it plays out. All right, let's do a wipe down on that note. We're about to walk through a full UI component that converts. Component's gonna turn out to be a funny old word. It refers to a function that associates, describes, captures in full the relationship between underlying data in JavaScript, in this case post and what the user sees.

That is a component, a full route through, a full pipeline through, from some underlying data through to what the user sees. It is a, I guess, description in whole of the content, what the user sees, how it depends on underlying data, and how the user is able to act on that data, sorry, act on what they see, click on it, and change data that's then gonna update what the user sees, the content, via a handler.

This is gonna be a full UI component. It's only taken us [LAUGH] But hey, at least we definitely know what it's doing. All right.

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