docs: remove old article outline/contents

This commit is contained in:
Corbin Crutchley
2023-12-14 05:21:21 -08:00
parent bd82de34d6
commit c840c70493
35 changed files with 0 additions and 20202 deletions

View File

@@ -1,42 +0,0 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# Compiled output
/dist
/tmp
/out-tsc
/bazel-out
# Node
/node_modules
npm-debug.log
yarn-error.log
# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history/*
# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
# System files
.DS_Store
Thumbs.db

View File

@@ -1,71 +0,0 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"DemoApp": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/demo-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"configurations": {
"production": {
"browserTarget": "DemoApp:build:production"
},
"development": {
"browserTarget": "DemoApp:build:development"
}
},
"defaultConfiguration": "development"
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "DemoApp:build"
}
}
}
}
}
}

View File

@@ -1,31 +0,0 @@
{
"name": "@unicorn-utterances/angular-reactivity",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"dev": "ng serve",
"start": "ng serve",
"build": "ng build",
"watch": "ng build --watch --configuration development"
},
"private": true,
"dependencies": {
"@angular/animations": "^16.2.0",
"@angular/common": "^16.2.0",
"@angular/compiler": "^16.2.0",
"@angular/core": "^16.2.0",
"@angular/forms": "^16.2.0",
"@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.2.0",
"rxjs": "~7.8.0",
"tslib": "^2.3.0",
"zone.js": "~0.13.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.2.10",
"@angular/cli": "^16.2.10",
"@angular/compiler-cli": "^16.2.0",
"typescript": "~5.1.3"
}
}

View File

@@ -1,8 +0,0 @@
<html>
<head>
<title>Angular Reactivity</title>
</head>
<body>
<app-root></app-root>
</body>
</html>

View File

@@ -1,25 +0,0 @@
import "zone.js/dist/zone";
import { bootstrapApplication } from "@angular/platform-browser";
import { Component } from "@angular/core";
import { NgFor } from "@angular/common";
@Component({
selector: "app-root",
standalone: true,
imports: [NgFor],
template: `
<button (click)="count = count + 1">Add one to: {{ count }}</button>
<button (click)="count = count - 1">Remove one from: {{ count }}</button>
<ul id="list">
<li *ngFor="let item of [].constructor(count); let i = index">
List item {{ i }}
</li>
</ul>
`,
})
export class AppComponent {
count = 0;
}
bootstrapApplication(AppComponent);

View File

@@ -1,10 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./out-tsc/app",
"types": []
},
"files": ["src/main.ts"],
"include": ["src/**/*.d.ts"]
}

View File

@@ -1,30 +0,0 @@
/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"moduleResolution": "node",
"importHelpers": true,
"target": "ES2022",
"module": "ES2022",
"useDefineForClassFields": false,
"lib": ["ES2022", "dom"]
},
"angularCompilerOptions": {
"enableI18nLegacyMessageIdFormat": false,
"strictInjectionParameters": true,
"strictInputAccessModifiers": true,
"strictTemplates": true
}
}

View File

@@ -12,313 +12,6 @@
}
---
# What is Reactivity?
> This article is intended for newcomers to HTML and JavaScript programming. However, it's suggested that you read [this article explaining what the DOM is](/posts/understanding-the-dom) first.
As an experienced frontend engineer, I'm often asked:
> "Why would you want to use a modern frontend framework like React, Angular, or Vue?"
While [I have a whole (free) book on the topic](https://framework.guide), my short answer is typically "Reactivity". The follow-up response I usually get from this is:
> "What is reactivity?"
In short, **Reactivity is the ability to reflect what's in your JavaScript application's memory on the DOM as HTML**.
See, when you're building a website using only static HTML, the output to the DOM is straightforward.
```html
<!-- index.html -->
<main id="a">
<ul id="b">
<li id="c">Item 1</li>
<li id="d">Item 2</li>
</ul>
<p id="e">Text here</p>
</main>
```
![// TODO: Write alt](../understanding-the-dom/dom_tree.svg)
The problems start when we want to introduce interactivity into our output.
Let's build a small-scale application that:
- Has a button with a counter inside of it
- Start the counter at `0`
- Every time the button is clicked, add one to the counter
![// TODO: Write alt](./step_1.svg)
To do this, let's start with some HTML:
```html
<main>
<button id="add-button">Count: 0</button>
</main>
```
Then we can add in the required JavaScript to make the button functional:
```html
<script>
let count = 0;
const addBtn = document.querySelector('#add-button');
addBtn.addEventListener('click', () => {
count++;
addBtn.innerText = `Count: ${count}`;
});
</script>
```
<iframe data-frame-title="Example #1 - StackBlitz" src="uu-code:./step1-code?template=node&embed=1&file=index.html" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
## Adding a List
Not too bad, let's increase the difficulty a bit by:
- Adding an unordered list (`<ul>`)
- Every time `count` is increased, add a new `<li>` with a unique string inside
![// TODO: Write](./step_2.svg)
That might look something like this:
```html
<main>
<button id="add-button">Count: 0</button>
<ul id="list"></ul>
</main>
<script>
let count = 0;
const listEl = document.querySelector('#list');
function makeListItem(innerText) {
const li = document.createElement('li');
li.innerText = innerText;
listEl.append(li);
}
const addBtn = document.querySelector('#add-button');
addBtn.addEventListener('click', () => {
count++;
addBtn.innerText = `Count: ${count}`;
makeListItem(`List item: ${count}`);
});
</script>
```
<iframe data-frame-title="Example #2 - StackBlitz" src="uu-code:./step2-code?template=node&embed=1&file=index.html" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
## Removing items from the list
Okay! Things are heating up! For one last exercise, let's:
- Add a button that removes `1` from `count`
- When this button is pressed, remove the last element from the list
![// TODO: Write alt](./step_3.svg)
> Notice how complex our logic tree is getting?
```html
<main>
<button id="add-button">Add one to: 0</button>
<button id="remove-button">Remove one from: 0</button>
<ul id="list"></ul>
</main>
<script>
let count = 0;
const listEl = document.querySelector('#list');
function makeListItem(innerText) {
const li = document.createElement('li');
li.innerText = innerText;
listEl.append(li);
}
function removeListItem() {
listEl.lastChild.remove();
}
const addBtn = document.querySelector('#add-button');
const removeBtn = document.querySelector('#remove-button');
function updateBtnTexts() {
addBtn.innerText = `Add one to: ${count}`;
removeBtn.innerText = `Remove one from: ${count}`;
}
addBtn.addEventListener('click', () => {
count++;
updateBtnTexts();
makeListItem(`List item: ${count}`);
});
removeBtn.addEventListener('click', () => {
count--;
updateBtnTexts();
removeListItem();
});
</script>
```
<iframe data-frame-title="Example #3 - StackBlitz" src="uu-code:./step3-code?template=node&embed=1&file=index.html" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
> Wow! That got complex, quick, didn't it?!
Exactly... That leads me to the question:
## Shouldn't it be simpler?
Notice how each time we added another item that depended on `count`, our data didn't change. Instead, we had to add ever increasing levels of complexity to our codebase to glue our JavaScript state to the DOM representation of said state.
If we strip away all of this glue, we're left with a drastically simplified codebase:
```html
<main>
<button id="add-button">Add one to: 0</button>
<button id="remove-button">Remove one from: 0</button>
<ul id="list"></ul>
</main>
<script>
// Magical land where `count` changes auto-update the DOM
let count = 0;
addBtn.addEventListener('click', () => {
count++;
});
removeBtn.addEventListener('click', () => {
count--;
});
</script>
```
![// TODO: Write alt](./step_3_simplified.svg)
> Look at how many lines disappeared!
Not only is this nicer method of writing code theoretically possible, it's widely adopted by millions of developers via a frontend framework.
Some examples of frontend frameworks include:
- [React](https://react.dev/)
- [Angular](https://angular.dev/)
- [Vue](https://vuejs.org/)
These frameworks allow you to write code that focused on the data in JavaScript, rather than how it will be bound to the DOM:
<!-- tabs:start -->
### React
```jsx
const App = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Add one to: {count}</button>
<button onClick={() => setCount(count - 1)}>
Remove one from: {count}
</button>
<ul>
{Array.from({ length: count }).map((_, i) => (
<li>List item {i}</li>
))}
</ul>
</div>
);
};
```
<iframe data-frame-title="React Reactivity - StackBlitz" src="uu-code:./react-reactivity?template=node&embed=1&file=&file=src%2Fmain.jsx" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
### Angular
```typescript
@Component({
selector: "app-root",
standalone: true,
imports: [NgFor],
template: `
<button (click)="count = count + 1">Add one to: {{ count }}</button>
<button (click)="count = count - 1">Remove one from: {{ count }}</button>
<ul>
<li *ngFor="let item of [].constructor(count); let i = index">
List item {{ i }}
</li>
</ul>
`,
})
export class AppComponent {
count = 0;
}
```
<iframe data-frame-title="Angular Reactivity - StackBlitz" src="uu-code:./angular-reactivity?template=node&embed=1&file=src%2Fmain.ts" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
### Vue
```vue
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">Add one to: {{ count }}</button>
<button @click="count--">Remove one from: {{ count }}</button>
<ul id="list">
<li v-for="(_, i) of [].constructor(count)">List item {{ i }}</li>
</ul>
</template>
```
<iframe data-frame-title="Vue Reactivity - StackBlitz" src="uu-code:./vue-reactivity?template=node&embed=1&file=src%2FApp.vue" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin"></iframe>
<!-- tabs:end -->
This, dear reader, is the core idea behind reactivity: Allowing us to focus on how we want to change the state stored in JavaScript and allowing some other mechanism to abstract away _how_ it shows up on-screen.
These mechanisms can have wildly different methods to them, too!
For example, here's what each of the frameworks utilize under-the-hood:
| Framework | Reactivity Method | Rendering Method |
| --------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| React | [Explicit Function Calls](https://twitter.com/crutchcorn/status/1527059716907487232) | [VDOM](/posts/unraveling-the-magic-of-the-virtual-dom) |
| Angular | [Zone.js](/posts/angular-internals-zonejs) | [Incremental DOM](https://blog.angular.io/how-the-angular-compiler-works-42111f9d2549) |
| Vue | [Proxies](https://vuejs.org/guide/extras/reactivity-in-depth.html) | [VDOM](/posts/unraveling-the-magic-of-the-virtual-dom) |
> This is real nerd hours, don't feel bad if this just looks like gibberish to you right now.
## Conclusion
This has been a look at what reactivity is and why you might want to use a modern frontend framework to utilize it in your apps today.
Next time, we'll talk about what "Reconciliation" is and how it impacts most React and Vue frontend applications today.
Want a place to ask questions as you're learning on your journey? [Join our Discord](https://discord.gg/FMcvc6T) and let us know what you thought of this article. We'd love to get to know you!
# What is Reconciliation?
OK now "reconciliation"

View File

@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,9 +0,0 @@
<html>
<head>
<title>React Reactivity</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>

View File

@@ -1,19 +0,0 @@
{
"name": "@unicorn-utterances/react-reactivity",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.0.4",
"vite": "^4.4.9"
}
}

View File

@@ -1,22 +0,0 @@
import { createRoot } from "react-dom/client";
import { useState } from "react";
const App = () => {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>Add one to: {count}</button>
<button onClick={() => setCount(count - 1)}>
Remove one from: {count}
</button>
<ul>
{Array.from({ length: count }).map((_, i) => (
<li>List item {i}</li>
))}
</ul>
</div>
);
};
createRoot(document.getElementById("root")).render(<App />);

View File

@@ -1,6 +0,0 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
});

View File

@@ -1,12 +0,0 @@
<main>
<button id="add-button">Count: 0</button>
</main>
<script>
let count = 0;
const addBtn = document.querySelector('#add-button');
addBtn.addEventListener('click', () => {
count++;
addBtn.innerText = `Count: ${count}`;
});
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
{
"name": "@unicorn-utterances/step1-code",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.0.8"
}
}

View File

@@ -1,22 +0,0 @@
<main>
<button id="add-button">Count: 0</button>
<ul id="list"></ul>
</main>
<script>
let count = 0;
const listEl = document.querySelector('#list');
function makeListItem(innerText) {
const li = document.createElement('li');
li.innerText = innerText;
listEl.append(li);
}
const addBtn = document.querySelector('#add-button');
addBtn.addEventListener('click', () => {
count++;
addBtn.innerText = `Count: ${count}`;
makeListItem(`List item: ${count}`);
});
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
{
"name": "@unicorn-utterances/step2-code",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.0.8"
}
}

View File

@@ -1,40 +0,0 @@
<main>
<button id="add-button">Add one to: 0</button>
<button id="remove-button">Remove one from: 0</button>
<ul id="list"></ul>
</main>
<script>
let count = 0;
const listEl = document.querySelector('#list');
function makeListItem(innerText) {
const li = document.createElement('li');
li.innerText = innerText;
listEl.append(li);
}
function removeListItem() {
listEl.lastChild.remove();
}
const addBtn = document.querySelector('#add-button');
const removeBtn = document.querySelector('#remove-button');
function updateBtnTexts() {
addBtn.innerText = `Add one to: ${count}`;
removeBtn.innerText = `Remove one from: ${count}`;
}
addBtn.addEventListener('click', () => {
count++;
updateBtnTexts();
makeListItem(`List item: ${count}`);
});
removeBtn.addEventListener('click', () => {
count--;
updateBtnTexts();
removeListItem();
});
</script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
{
"name": "@unicorn-utterances/step3-code",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"vite": "^5.0.8"
}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 50 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 89 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 140 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 127 KiB

View File

@@ -1,24 +0,0 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -1,9 +0,0 @@
<html>
<head>
<title>Vue Reactivity</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,18 +0,0 @@
{
"name": "@unicorn-utterances/vue-reactivity",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.3.4"
},
"devDependencies": {
"@vitejs/plugin-vue": "^4.2.3",
"vite": "^4.4.9"
}
}

View File

@@ -1,13 +0,0 @@
<script setup>
import { ref } from "vue";
const count = ref(0);
</script>
<template>
<button @click="count++">Add one to: {{ count }}</button>
<button @click="count--">Remove one from: {{ count }}</button>
<ul id="list">
<li v-for="(_, i) of [].constructor(count)">List item {{ i }}</li>
</ul>
</template>

View File

@@ -1,5 +0,0 @@
// main.js
import { createApp } from "vue";
import App from "./App.vue";
createApp(App).mount("#root");

View File

@@ -1,6 +0,0 @@
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
export default defineConfig({
plugins: [vue()],
});