[WIP] The Hard Parts of UI development
Published: 2024-01-14 22:59:25

Notes from the course `The Hard Parts of UI Development` by Will Sentance in [Frontendmasters](https://frontendmasters.com/courses/hard-parts-ui-dev/). 

#### Goal 1 - Display content on the screen

- `Layout engine` works out page layout for specific browser/screen.
- `Render engine` produces the composite ‘image’ for graphics card.
- `html` > `DOM` in `C++` (webcore) > visual content. `html` is a one time addition of elements into the DOM. 
- `CSS` > `CSSOM` (mirrors the `DOM`) in `C++` > styling the content above
- Render engines creates an image of the page, which gets sent to the graphics card and updated 60 times a second.

#### Goal 2 - Let users change the content / interact with it

- `html` is a one time addition of elements to the `DOM` (in C++). Changing content on the screen changes the DOM. However, we cannot run code on the DOM. Javascript is needed.
- When we load a url in the browser: 1) we open the html file, `html` is parsed by the `html parser` and creates the DOM (in C++); 2) the html file has a reference to the JS file, which will start loading by the JS engine, with its own thread of execution, memory, execution context, etc.; 3) JS links to the C++ DOM runtime via the `document` object and all the methods available to it: `document.querySelector`, etc.
- `Web IDL` (`Interface Description Language`) - standardised way to know how to access other parts of the browser from JS. `DOM API` is written in human language - its implementation in the browser will be described in the `Web IDL`. 
- `const jsDiv = document.querySelector('div')` uses the `document` object, which will give us access to the `DOM API` via a hidden link to the C++ DOM. It will allow us to grab a list of elements in C++. `jsDiv` will be assigned to the evaluation of `document.querySelector('div')`. That will be an object with properties that allow us to access and modify the C++ DOM element i.e. `textContent`. If we console log that element, instead of the C++ DOM element we get the html command that created the C++ DOM element!
- `textContent` is the property of `jsDiv` in the document object that will update the DOM So it is a `getter setter` property, otherwise it would be confined to this object and would be of little use to us. ` other` and others get added to the call stack.
- The following code follows the steps described after:

```
// in app.html
<input />
<div></div>
<script src='app.js'></script>

// in app.js
let post = '';

const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');

function handleInput() {
     post = jsInput.value;
     jsDiv.textContext = post;
}

jsInput.onInput = handleInput;
```

- `app.html` loads; the `HTML parser` looks at each line and adds them to the C++ DOM from which we will produce the actual pixels of the webpage through the `layout and render engine`; the `HTML parser` will tee up the JS engine to run; this will give us access to the `document` object that has a reference to the C++ object, that we can run function on to search or add elements.
- There is a division between "C++ land" and JS land (we are not able to write code directly into the C++ land. Once the HTML is parsed and the items added in the C++ object, the items appear in the screen.
- When JS starts executing, we get a call stack and a global execution context, which has a pre-loaded object: `document`. This object allow our JS to interact with the C++ object: `querySelector` (this is one type of `accessor object`), etc. They not only have action in JS but also in the C++ object.
- The JS above: 1) define const post assigned to empty string 2) `document.querySelector('input')` will call the `querySelector` getter/setter in the document object, which will bring us to the C++ object 3) it finds it but because the C++ object cannot be brought back a corresponding object gets produced in JS with a link to the underlying C++ object; 4) that newly produced object is assigned to `jsInput`; 5) that JS object has properties that will allow us to work with the C++ object: i.e. `onInput`, `value`, etc.; 6) same for `jsDiv`; 7) assign `handleInput` to a function declaration; 8) in the `jsInput` JS object representation of the C++ element we will use the setter `onInput` to assign it to the function declaration `handleInput`. That will add a handler in the C++ element that will trigger the execution of that function when a user inputs something in the `input` C++ object element; 9) user action writes something in the input (ie. "Hi") and that triggers an `event` which issues a command to the C++ element to execute its handler; 10) `value` in the `input` C++ element will be populated with `Hi`; 11) the Events API will trigger the function referenced in the C++ element handler and add the call to `handleInput` in the callback queue; 12) the `event loop` will grab that function execution from the callback queue when the call stack is empty and there i no more JS code to run in the global execution context; 13) the function call will be added it to the `call stack`; 14) an `execution context` will be created with its memory; 15) in memory the variable `post` will be assigned to the value of the property `value` of the `jsInput` object; 16) we look inside the `jsDiv` object for the setter `textContext` which is set to the value of `post`; 17) `textContent` updates the value of the underlying C++ element, which in turn updates the screen to show "Hi".

#### One-way data binding

- It is a paradigm implemented by the frameworks (React, Vue, Angular, etc.) that restrict the back and forth between C++ and JS to make our lives easier as UI engineers. 
- Code:

```
// in app.html
<input />
<div></div>
<script src='app.js'></script>

// in app.js
let post = '';

const jsInput = document.querySelector('input');
const jsDiv = document.querySelector('div');

jsInput.value = 'What is on your mind?'; // view

function handleInput() {
     post = jsInput.value;
     jsDiv.textContext = post; // affect view!
}

function handleClick() {
     jsInput.value = ''; // affect view!
}

jsInput.onInput = handleInput;
jsInput.onClick = handleClick;
```

- `jsInput.value` sets the C++ value to the value set in JS and that renders the string in the screen; user action click input: sends an event to the DOM to trigger the handler which adds the function to the JS callback queue; event loop grabs the `handleClick` and adds it to the call stack; `handleClick` is called and an execution context is created; the `value` setter of `jsInput` gets sets to an empty string, updates the value in the C++ element, which updates the string; next user action: input; they will write whatever, which will trigger the C++ element handler, add the function to the callback queue, event loop will add it to the call stack, new execution context, the `value` property of the `jsInput` object will be assigned to `post`, and that string will be set to the `textContent` setter, which updates the C++ element, which updates the screen.