A presentation at VueConf Toronto by Sarah Dayan
Finite State Machines in Vue 3
In web apps, state is everywhere.
State can be strings, numbers 1 <template> 2 <p>My name is {{ name }} and I’m {{ age }} years old.</p> 3 4 5 6 7 8 9 10 11 12 13 14 15 16 </template> <script> import { ref, computed } from “vue”; export default { setup() { const name = ref(“Sarah Dayan”); const birthYear = ref(1990); const age = computed(() => new Date().getYear() - birthYear.value); return { name, age }; }, };
State can be arrays, objects 1 <template> 2 <p>My favorite snacks are:</p> 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<ul> <li v-for=”{ label, emoji } in food” :key=”label”> {{ label }} ({{ emoji }}) </li> </ul> </template> <script> import { ref } from “vue”; export default { setup() { const food = ref([ { label: “croissant”, emoji: ” 🥐 ” },State can be booleans 1 <template> 2 <p>I have a secret…</p> 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<p v-if=”shouldReveal”>{{ secret }}</p> <button v-else @click=”reveal”>Please tell!</button> </template> <script> import { ref } from “vue”; export default { setup() { const shouldReveal = ref(false); const secret = ref(“Don’t repeat it!”); function reveal() { shouldReveal.value = true;Data fetching with loading state 1 export default { 2 setup() { 3 const { data, loading, error } = toRefs( 4 reactive({ data: [], loading: true, error: null }) 5 ); 6 7 fetch(“https://example.com/api/users”) 8 .then((users) => (data.value = users)) 9 .catch((err) => (error.value = err)) 10 .finally(() => (loading.value = false)); 11 12 return { data, loading, error }; 13 }, 14 };
Data fetching with loading state 1 export default { 2 setup() { 3 const { data, loading, error } = toRefs( 4 reactive({ data: [], loading: true, error: null }) 5 ); 6 7 fetch(“https://example.com/api/users”) 8 .then((users) => (data.value = users)) 9 .catch((err) => (error.value = err)) 10 .finally(() => (loading.value = false)); 11 12 return { data, loading, error }; 13 }, 14 };
Data fetching with loading state 1 export default { 2 setup() { 3 const { data, loading, error } = toRefs( 4 reactive({ data: [], loading: true, error: null }) 5 ); 6 7 fetch(“https://example.com/api/users”) 8 .then((users) => (data.value = users)) 9 .catch((err) => (error.value = err)) 10 .finally(() => (loading.value = false)); 11 12 return { data, loading, error }; 13 }, 14 };
Data fetching with loading state 1 export default { 2 setup() { 3 const { data, loading, error } = toRefs( 4 reactive({ data: [], loading: true, error: null }) 5 ); 6 7 fetch(“https://example.com/api/users”) 8 .then((users) => (data.value = users)) 9 .catch((err) => (error.value = err)) 10 .finally(() => (loading.value = false)); 11 12 return { data, loading, error }; 13 }, 14 };
Data fetching with loading state 1 export default { 2 setup() { 3 const { data, loading, error } = toRefs( 4 reactive({ data: [], loading: true, error: null }) 5 ); 6 7 fetch(“https://example.com/api/users”) 8 .then((users) => (data.value = users)) 9 .catch((err) => (error.value = err)) 10 .finally(() => (loading.value = false)); 11 12 return { data, loading, error }; 13 }, 14 };
Data fetching with loading state 1 <template> 2 <div v-if=”loading”>Loading users…</div> 3 <table v-if=”data.length”> 4 <td :key=”user.id” v-for=”user in data”> 5 <div>{{ user.name }}</div> 6 <div>{{ user.email }}</div> 7 </td> 8 </table> 9 <div v-if=”error”>Uh-ho! Something unexpected happened.</div> 10 </template>
Data fetching with loading state 1 <template> 2 <div v-if=”loading”>Loading users…</div> 3 <table v-if=”data.length”> 4 <td :key=”user.id” v-for=”user in data”> 5 <div>{{ user.name }}</div> 6 <div>{{ user.email }}</div> 7 </td> 8 </table> 9 <div v-if=”error”>Uh-ho! Something unexpected happened.</div> 10 </template>
Data fetching with loading state 1 <template> 2 <div v-if=”loading”>Loading users…</div> 3 <table v-if=”data.length”> 4 <td :key=”user.id” v-for=”user in data”> 5 <div>{{ user.name }}</div> 6 <div>{{ user.email }}</div> 7 </td> 8 </table> 9 <div v-if=”error”>Uh-ho! Something unexpected happened.</div> 10 </template>
Data fetching with loading state 1 <template> 2 <div v-if=”loading”>Loading users…</div> 3 <table v-if=”data.length”> 4 <td :key=”user.id” v-for=”user in data”> 5 <div>{{ user.name }}</div> 6 <div>{{ user.email }}</div> 7 </td> 8 </table> 9 <div v-if=”error”>Uh-ho! Something unexpected happened.</div> 10 </template>
Data fetching with loading state 1 const { data, loading, error } = toRefs( 2 reactive({ data: [], loading: true, error: null }) 3 4 5 6 7 8 9 10 11
); fetch(“https://example.com/api/users”) .then((users) => (data.value = users)) .catch((err) => (error.value = err)); // loading.value is still true
return { data, loading, error };
Imperative code is more error-prone.
We should only control the what, not the how.
We should only control the what, not the how.
State machines.