Lab 5
II

MIT Interactive Visualization & Society course

Reactivity

If you’ve used a spreadsheet, you already know what reactivity is. The core idea of reactivity is that when a value changes, all dependent values are updated automatically.

CSS is reactive

As we have already seen, CSS is reactive. For example, if we update a CSS variable via JS, everything that depends on it (including other variables) is updated automatically.

JS is not reactive


				a:hover {
					background: gold;
				}
			

				<a href="#">Come here</a>
			

				<a href="#"
				   onmouseover="this.style.background = 'gold';"
				>Come here</a>
			

				<a href="#"
				   onmouseover="this.style.background = 'gold';"
				   onmouseout="this.style.background = '';"
				>Come here</a>
			
Remember this? As a part of CSS pseudo-classes are reactive: not only does the background here become `gold` when the link is hovered, but it also returns to its previous state automatically, when the link stops being hovered. However, when we use JS to do the same thing, we have to manually set the background back to its original value ourselves.

Implenting reactivity is hard

+ =

			<input type="number" id="input_a"> +
			<input type="number" id="input_b"> =
			<input type="number" id="input_c" disabled>
		

Reactivity with vanilla JS


			let a = 1, b = 2, c;
			input_a.value = a;
			input_b.value = b;

			input_a.addEventListener("input", e => {
				a = Number(input_a.value);
				updateC();
			});
			input_b.addEventListener("input", e => {
				b = Number(input_b.value);
				updateC();
			});

			function updateC() {
				c = a + b;
				input_c.value = c;
			}

			updateC();
		
The naîve approach to implementing reactivity ourselves is to add event listeners to everything that could possibly change, and update everything that may have been affected. This gets very complicated very fast, since we need to keep track of all the dependencies and update them all manually. [Live demo](https://codepen.io/leaverou/pen/OJGMyvQ)

Reactivity with vanilla JS Part 2


			let a = 1, b = 2, c;
			input_a.value = a;
			input_b.value = b;

			function render() {
				a = Number(input_a.value);
				b = Number(input_b.value);
				c = a + b;
				input_c.value = c;
			}

			render();
			input_a.addEventListener("input", render);
			input_b.addEventListener("input", render);
			document.body.addEventListener("input", render);
		
Because this is so tedious, what we end up doing instead is is bunching updates together and updating more things than we need to, often everything at once with a single function. Then, every time anything updates, we call that single function and update *everything*. With that approach, we could even listen to the `input` event on an ancestor, since it [*bubbles*](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_bubbling), a practice known as [event delegation](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#event_delegation). However, the more complex the app, the slower this practice becomes, as we are updating more than we need to. Also, this makees it impossible to implement *two-way binding*, i.e. also update the input when the value changes, not just the other way around. [Live demo](https://codepen.io/leaverou/pen/OJGMydE)

Reactivity boils down to recalculation

There is one clear theme in both previous examples: Implementing reactivity boils down to recalculating things. The tricky bit is knowing *what* to recalculate and *when*. The what is typically implemented with a [*dependency graph*](https://en.wikipedia.org/wiki/Dependency_graph). When a value changes, we recalculate everything that depends on it, and everything that depends on those, and so on. The when is typically implemented with *events* when it’s about updating data from user actions, and [accessors](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors) and [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) when it's about updating the UI from data. Thankfully, reactive JS frameworks abstract all this complexity away from us. So how would the little adder be implemented in Svelte?

Reactivity in Svelte

[Live demo](https://svelte.dev/repl/28edd440c5c94741ae93e4c123c3503c?version=4.2.12)

All blocks are reactive

[Live demo](https://svelte.dev/repl/13a63d23781848a2a23570c308de03a8?version=4.2.12)

Reactive statements

[Live demo](https://svelte.dev/repl/d07ade3804ec4272b9513b2f956d9e76?version=4.2.12)

			<script>
				let a = 1, b = 2, c;
				$: c = a + b;
			</script>

			<input type="number" id="a" bind:value={a}> +
			<input type="number" id="b" bind:value={b}> =
			<input type="number" id="c" bind:value={c} disabled>
		
Reactivity in Svelte boils down to two primitives: 1. The `$:` prefix, which tells Svelte that this is a [*reactive statement*](https://learn.svelte.dev/tutorial/reactive-declarations) that should be recalculated whenever its dependencies change. 2. The [`bind:` directive](https://svelte.dev/docs/element-directives#bind-property), which tells Svelte to update the input whenever the value changes, and vice versa.

What is a Web API?

Websites are for humans

APIs are for programs


			{
				"id": "cuisine-of-nepal-san-francisco",
				"name": "Cuisine of Nepal",
				"image_url": ...,
				"is_closed": false,
				"url": ...,
				"review_count": 303,
				"categories": [...],
				"rating": 4.5,
				"coordinates": {...},
				"transactions": [
					"delivery",
					"pickup",
					"restaurant_reservation"
				],
				"price": "$$",
				"location": {...},
				"phone": "+14156472222",
				"display_phone": "(415) 647-2222",
				"distance": 2502.5961202999997,
				"attributes": {
					"gender_neutral_restrooms": true
				},
				"data": {
					"reservation_openings": [
						"13:30",
						"13:45",
						"14:00"
					]
				}
			},
		

Async values


		let response = await fetch("https://api.github.com/users/leaverou");
		let json = await response.json();
		// Do stuff with json
	

		fetch("https://api.github.com/users/leaverou")
			.then(response => response.json())
			.then(json => {
				// Do stuff with json
			});
	
Many functions in JS cannot return a result within a reasonable amount of time. For example, [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/fetch) sends an arbitrary HTTP request and reads the response. This can take a long time. To avoid blocking execution, we use *asynchronous* functions, which return a [*promise*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises) which will eventually have the value we want. In fact, using `fetch()` involves two promises: one for the response, and one for the JSON data.

Svelte {#await}


		{#await promise}
			Loading…
		{:then result}
			Result was: { JSON.stringify(result) }
		{:catch error}
			Error: {error.message}
		{/await}
	

Time to get our hands dirty!

Today’s menu:

👩🏽‍💻🧑🏼‍💻👨🏻‍💻