1 of 41

Metaphysics and JavaScript

@rich_harris • Aug 2019

2 of 41

better

Svelte is better than React

go on, tweet this slide without context

i live for the drama

3 of 41

objectively

Svelte is objectively better than React

Svelte, as a compiler, results in apps that are much smaller and faster to start than traditional runtime frameworks

“Computer, Build Me an App”

JSConf EU, June 2018, Berlin

4 of 41

objectively

Svelte is objectively better than React

By eliminating the virtual DOM, apps become many times faster — especially critical on low-powered devices

“Rethinking Reactivity”

YGLF, April 2019, Israel

5 of 41

objectively

Svelte is objectively better than React

Designing a component language from first principles allows us to write leaner, clearer, more robust code

“The Return of ‘Write Less, Do More’”

JSCamp, July 2019, Barcelona

6 of 41

subjectively

Svelte is... subjectively better than React?

7 of 41

ui = f(state)

8 of 41

State-driven UI is easier to reason about

9 of 41

10 of 41

Pure UI

“With this model in place, the programmer is thus relieved from the burden of specifying the transition between states (or transformation) of the UI over time. No need to specify how to go from A to B: just describe what A looks like and what B looks like, in a discrete way.”

–Guillermo Rauch, rauchg.com/2015/pure-ui

11 of 41

Functional UI !== State-driven UI

12 of 41

People are horny for functions.

13 of 41

No man steps in the same river twice,

for it is not the same river

and he is not the same man

—Heraclitus

14 of 41

The Theory

of Forms

15 of 41

The Allegory of the Cave

16 of 41

<form></form>

17 of 41

18 of 41

The Ship of Theseus

19 of 41

ui = f(state)

ui1 = <App state={state1}/>

ui2 = <App state={state2}/>

ui1 !== ui2

20 of 41

21 of 41

22 of 41

So why wouldn’t we embrace this ideology?

ui = f(state)

“An ideology is a collection of normative beliefs and values that an individual or group holds for other than purely epistemic reasons.”

—Wikipedia

ideological statement

23 of 41

const render = state => {

document.body.innerHTML = `

<h1>Hello ${state.name}!</h1>

<input value="${state.name}">

`;

const input = document.querySelector('input');

input.oninput = () => {

render({

name: input.value

});

};

};

render({ name: 'world' });

24 of 41

const render = state => {

document.body.innerHTML = `

<h1>Hello ${state.name}!</h1>

<input value="${state.name}">

`;

const input = document.querySelector('input');

input.oninput = () => {

render({

name: input.value,

focus: document.activeElement === input

});

};

if (state.focus) input.focus();

};

render({ name: 'world' });

25 of 41

const render = state => {

document.body.innerHTML = `

<h1>Hello ${state.name}!</h1>

<input value="${state.name}">

`;

const input = document.querySelector('input');

input.oninput = () => {

render({

name: input.value,

focus: document.activeElement === input,

selectionStart: input.selectionStart,

selectionEnd: input.selectionEnd,

selectionDirection: input.selectionDirection

});

};

if (state.focus) input.focus();

input.setSelectionRange(

state.selectionStart || 0,

state.selectionEnd || 0,

state.selectionDirection || 'none'

);

};

render({ name: 'world' });

26 of 41

const render = state => {

document.body.innerHTML = `

<style>

h1 {

animation: fade-in 1s;

}

@keyframes fade-in {

from { opacity: 0 }

to { opacity: 1 }

}

</style>

<h1>Hello ${state.name}!</h1>

<input value="${state.name}">

`;

const input = document.querySelector('input');

input.oninput = () => {

render({

name: input.value,

focus: document.activeElement === input,

selectionStart: input.selectionStart,

selectionEnd: input.selectionEnd,

selectionDirection: input.selectionDirection

});

};

if (state.focus) input.focus();

input.setSelectionRange(

state.selectionStart || 0,

state.selectionEnd || 0,

state.selectionDirection || 'none'

);

};

render({ name: 'world' });

27 of 41

const App = () => {

const [name, setName] = useState('world');

return (

<>

<h1>Hello {name}!</h1>

<input onChange={e => setName(e.target.value)}>

</>

);

};

render(<App/>, document.body);

28 of 41

29 of 41

class Clock extends React.Component {

state = {

count: 0

}

componentDidMount() {

this.interval = setInterval(() => {

this.setState({

count: this.state.count + 1

});

}, 1000);

}

componentDidUpdate() {

console.log(this.state.count);

}

componentDidUnmount() {

clearInterval(this.interval);

}

render() {

return (

<p>Count: {this.state.count}</p>

);

}

}

30 of 41

31 of 41

function Clock() {

const [count, setCount] = useState(0);

// componentDidMount / componentDidUnmount

useEffect(() => {

const interval = setInterval(() => {

setCount(count + 1);

}, 1000);

return () => {

clearInterval(interval);

};

}, []);

// componentDidUpdate

useEffect(() => {

console.log(count);

}, [count]);

return (

<p>Count: {count}</p>

);

}

32 of 41

33 of 41

34 of 41

—Dan Abramov, overreacted.io

35 of 41

36 of 41

37 of 41

38 of 41

39 of 41

it

he

No man steps in the same river twice,

for it is not the same river

and he is not the same man

—Heraclitus

40 of 41

dEmO tImE!!1!

41 of 41

Thanks!