Observable
(state)
Computed
(side-effect)
PureComputed
(derived state)
A Journey into Reactive JavaScript.
Kalwabed Rizki
"The essence of functional reactive programming is to specify the dynamic behavior of a value completely at the time of declaration"
Heinrich Apfelmus, via Michel Weststrate
"Reactive Programming is a declarative programming paradigm built on data-centric event emitters."
Ryan Carniato, in "What the hell is Reactive Programming anyway?"
var foo = 10; var bar = foo + 1; foo = 11; bar = foo + 1;
var foo = 10; var bar = foo + 1; foo = 11; bar = foo + 1;
foo
and bar
are brothers. bar
is dependent on foo
for support.
When foo
changes, bar
does not.
foo
had to stabilize the relationship between them again, and it wouldn’t be for long.
and someone has discovered something called destiny operator.
with destiny operator.
var foo = 10; var bar <== foo + 1; foo = 20; Assert.AreEqual(21, bar);
var foo = 10; var bar <== foo + 1; foo = 20; Assert.AreEqual(21, bar);
Some say that when the compiler encounters code that changes foo
, it inserts the corresponding change for bar
, such that they are always in sync.
"I have no time. Please explain it to me like I’m five."
a = b + c
a = b + c
The value of a
will change every time the value of b
or c
variable changes.
15
Signals are the main players in what is called the reactive system.
It consists of a:
But the key difference is how it manages its subscriptions.
We have partner in crime called Reactions and Derivations.
Reactions are functions that are called when a signal changes.
import { ref, watchEffect } from 'vue' console.log("1. Create Signal"); const count = ref(0); console.log("2. Create Reaction"); watchEffect(() => console.log("The count is", count.value)) console.log("3. Set count to 10"); count.value = 10 /* outputs 1. Create Signal 2. Create Reaction The count is 0 3. Set count to 10 The count is 10 /*
import { ref, watchEffect } from 'vue' console.log("1. Create Signal"); const count = ref(0); console.log("2. Create Reaction"); watchEffect(() => console.log("The count is", count.value)) console.log("3. Set count to 10"); count.value = 10 /* outputs 1. Create Signal 2. Create Reaction The count is 0 3. Set count to 10 The count is 10 /*
Derivations are signals that are derived from other signals.
import { ref, watchEffect } from 'vue' console.log("1. Create Signals"); const firstName = ref("John"); const lastName = ref("Smith"); const fullName = () => { console.log("Creating/Updating fullName"); return `${firstName.value} ${lastName.value}` }; console.log("2. Create Reactions"); watchEffect(() => console.log("My name is", fullName())) watchEffect(() => console.log("Your name is not", fullName())); console.log("3. Set new firstName"); firstName.value = "Jacob";
import { ref, watchEffect } from 'vue' console.log("1. Create Signals"); const firstName = ref("John"); const lastName = ref("Smith"); const fullName = () => { console.log("Creating/Updating fullName"); return `${firstName.value} ${lastName.value}` }; console.log("2. Create Reactions"); watchEffect(() => console.log("My name is", fullName())) watchEffect(() => console.log("Your name is not", fullName())); console.log("3. Set new firstName"); firstName.value = "Jacob";
/* outputs 1. Create Signals 2. Create Reactions Creating/Updating fullName My name is John Smith Creating/Updating fullName Your name is not John Smith 3. Set new firstName Creating/Updating fullName My name is Jacob Smith Creating/Updating fullName Your name is not Jacob Smith */
/* outputs 1. Create Signals 2. Create Reactions Creating/Updating fullName My name is John Smith Creating/Updating fullName Your name is not John Smith 3. Set new firstName Creating/Updating fullName My name is Jacob Smith Creating/Updating fullName Your name is not Jacob Smith */
import { ref, watchEffect, computed } from 'vue' console.log("1. Create Signals"); const firstName = ref("John"); const lastName = ref("Smith"); const fullName = computed(() => { console.log("Creating/Updating fullName"); return `${firstName.value} ${lastName.value}` }); console.log("2. Create Reactions"); watchEffect(() => console.log("My name is", fullName())) watchEffect(() => console.log("Your name is not", fullName())); console.log("3. Set new firstName"); firstName.value = "Jacob";
import { ref, watchEffect, computed } from 'vue' console.log("1. Create Signals"); const firstName = ref("John"); const lastName = ref("Smith"); const fullName = computed(() => { console.log("Creating/Updating fullName"); return `${firstName.value} ${lastName.value}` }); console.log("2. Create Reactions"); watchEffect(() => console.log("My name is", fullName())) watchEffect(() => console.log("Your name is not", fullName())); console.log("3. Set new firstName"); firstName.value = "Jacob";
Things that are often discussed in the frontend world are usually about performance and rendering.
One of the issues that often comes up when discussing these two things is how to manage the state.
Traditional global state with React.
Global state with React context.
It’s simple, we don’t.
Library & framework - examples.
What about React?
Meanwhile, you can get a reactive experience in React using third-party libraries like @preact/signals-react or MobX.
Slides can be found on kalwabed.xyz/talks