If you want to manage a simple global state and didn't want to use Vuex, we can use the reactive and toRefs properties from the Vue 3 Composition API to compose our own lightweight state management.
We can start off by writing our useTodos
hook that will contain our state logic.
// store/todos.js
import { reactive, toRefs } from "vue";
const url = 'https://jsonplaceholder.typicode.com/todos';
const state = reactive({
todos: [],
loading: true,
selectedTodo: null
});
export default function useTodos() {
const fetchTodos = async () => {
state.loading = true;
state.todos = await (await fetch(url)).json();
state.loading = false;
}
return {
...toRefs(state), // convert to refs when returning
fetchTodos
}
}
The area of focus in the code above is the reactive
and toRefs
properties.
The reactive
property, from the docs, takes an object and returns a reactive proxy of the original. This is equivalent to 2.x's Vue.observable()
.
The toRefs
property converts the reactive
object to a plain object and lets the consuming component destructure / spread the returned object from a composition function (useTodos
) without losing reactivity.
Next, we can go to our consuming component, App.vue
for example, and import our composition function.
App.vue
<template>
<h1 v-if="loading">Loading...</h1>
<div v-else>
<SelectedTodo />
<ul>
<li v-for="t in todos" :key="t.id" @click="selectedTodo = t">{{t.title}}</li>
</ul>
</div>
</template>
<script>
import { onMounted } from "vue";
import useTodos from "./store/todos";
import SelectedTodo from "./components/SelectedTodo.vue";
export default {
name: "App",
components: { SelectedTodo },
setup() {
const { todos, fetchTodos, selectedTodo, loading } = useTodos();
onMounted(() => {
fetchTodos();
});
return {
todos,
selectedTodo,
loading,
};
},
};
</script>
SelectedTodo.vue
<template>
<pre>
{{ JSON.stringify(selectedTodo, undefined, 4) }}
</pre>
</template>
<script>
import useTodos from "../store/todos";
export default {
setup() {
const { selectedTodo } = useTodos();
return {
selectedTodo,
};
},
};
</script>
Let's break down what we've written in App.vue
:
First, we imported our composition function, destructured and returned so that it will be available for the rest of the component.
The onMounted
lifecycle method was used to fetch our todos and we display the result in an unordered list. Each item is clickable and will set the value of the selectedTodo
state to the selected item.
Lastly, we created a SelectedTodo.vue
component just to show that the selectedTodo
property is reactive.
Probably the most interesting part here is that we can reuse our hook in different components and they will get all the updates of our state.
Thanks for reading!
Top comments (2)
Thanks for sharing, looks pretty easy 🙌
It's very useful thanks.