How to use Composition API instead of Vuex in Vue3 and also in Vue2.
Tags: vue, vuex, frontend
Published: 2022-01-26 00:54:28

---
title: How to use Composition API instead of Vuex in Vue3 and also in Vue2.
published: true
description: We are going to understand how we can replace Vuex functionality by Composition API.
tags: Vue, Vuex, Frontend
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jpall6wqhe20jo7xq5th.jpeg
---

#Why?

Often we develop some components that have access to a global state. For example, there are many separate components to filter some items, but these items have to be consistent. Or your application has user info, that has to use in different places. So, the main reason for using a global store (shareable reactive object) is just to apply more flexibility to your project.

Nowadays, Vuex has solved this problem very well. And it can do it today. In this article, we just discuss a new alternative and an interesting applying of a new `composition-api`.

#Vuex

Before we dive into the Composition API let me to remind you about two main points of Vuex **(and other Flux libraries that allow us to use shareable state in our app)**

Our store has to be reactive. It means all templates of each component that use some variable from store has to update its template after variable update in store.
The only way of mutating shareable store is to execute mutations, some functions that work with the store. It's important for Vuex because it allows tracking all changes. Read more in [docs](https://vuex.vuejs.org/guide/#getting-started)

#Composition API

Now, let's take a look at new features in Vue3 `Composition API`. There are tools to create real reactive objects like a Vuex store

There are `ref` and `reactive`. ref returns wrapped reactive object with value field. It's good for some alone variables. But reactive method returns a reactive object. And we can use it exactly like a state in Vuex. Actually, when you return an object from data() in your component, internally Vue uses the reactive method to make this object reactive.

Now we also can use it directly. Just import the reactive method from vue3 or if you still use Vue2 from a separate npm package @vue/composition-api. Yes, as you could see from title of the article we can already use it even in Vue2.

Npm package: [@vue/composition-api](https://github.com/vuejs/composition-api)

If you don't use Vue3 install `@vue/composition-api` as a plugin globally.

```js
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```

Now we can use a `reactive` function in any component, but I advise you to create a separate file for our store.

If you already use `Vue3` then just import `reactive` directly from `vue`. When you migrate to Vue3 you can just replace @vue/composition-api to vue

*The whole complete project of example that is used in this article is in Sandbox*

```js
Vue2Vue3
// store.js
import { reactive } from '@vue/composition-api'
```

#Creating a reactive store

Let's create a new reactive store for searching by parameters. They will share across whole application and we can use it in any component.

```js
// store.js
import { reactive } from "vue"

const state = reactive({
  keyWord: ""
})

export const store = {
  state
}
```js

Actually, we can use it right away in our components. Just add the store in each component that has to use the reactive object with property `keyWord`. For example, I made two identical components and place them into one another component. This is code for `ComponentA` and `ComponentB` (They have the same code)

```vue
<template>
  <div>
    <input v-model="store.state.keyWord" />
  </div>
</template>

<script>
import { store } from "../store";

export default {
  data() {
    return {
      store,
    };
  },
};
</script>
```

We implemented the first point of `Vuex`, we have a reactive store and each template updates when something changes in the global store. You can play with it on the [Sandbox](https://codesandbox.io/s/awesome-cache-h9r30?file=/src/components/ComponentA.vue).

#One-Way Data Flow

*As a Vue developer, you probably know that we have to avoid direct mutation of `props`. One-way Data Flow prevents child components from accidentally mutating the parent’s state, which can make your app’s data flow harder to understand (from Vue Docs) [One-Way Data Flow in Vue Doc](https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow)*

Also, there is the second point of Vuex ideology: *The only way of mutating sharable store is to execute mutations.*

And, by the way, you should understand, we can work with our store now only because we import whole reactive store object and in `data` of our components it **passes by link**! We can't do the same "reactive" things with only one property. For instance, we can't do something like that:

```js
data() {
  return {
    keyWord: store.state.keyWord
  }
}
```

Now it's passed by value, and by the way, when we do this, we access the value and we can use it like value by default. But we can't change it in store. We have to change `store.state.keyWord` because the `store` is an object and it's passed by link. That's why our examples worked. You can also do the same trick with `props`, you can wrap it into an object and pass the whole object via props, BUT Vue will show you a warning about `avoiding direct mutation props`.

There are no warnings for changing reactive objects from another component. But I think according to One-Way Data Flow ideology and Vuex mutations we should apply this methodology to our examples. Let's use the best practices.

#Mutations

So, let's create a special function that can change the `state` when we invoke this function. Add function `changeKeyWord` into the `store.js` file and add it into an `export` statement at the bottom of the file.

```js
// store.js
import { reactive } from "vue"

const state = reactive({
  keyWord: ""
})

function changeKeyWord(value) {
  state.keyWord = value
}

export const store = {
  state,
  changeKeyWord
}
```

Now we can use the `changeKeyWord` function in our components.

```vue
// ComponentA.vue & ComponentB.vue
<template>
  <div>
    <input :value="keyWord" @input="changeKeyWord" />
  </div>
</template>

<script>
import { store } from "../store";

export default {
  data() {
    return {
      store,
      keyWord: store.state.keyWord,
    };
  },
  methods: {
    changeKeyWord(evt) {
      this.store.changeKeyWord(evt.target.value);
    },
  },
};
</script>
```

Now we have a local `keyWord` value in `data` from the store and we can change the value in the store by invoking the `changeKeyWord` function like `Mutation` in Vuex. But as you can notice, we can still change keyWord directly.

There is a good feature to disable direct mutation of our state. Special readonly function. It is also in composition-api. So we can just import it and use it in our store file.

```js
// store.js
import { reactive, readonly } from "vue"

const state = reactive({
  keyWord: ""
})

function changeKeyWord(value) {
  state.keyWord = value
}

export const store = readonly({
  state,
  changeKeyWord
})
```

#Getters

Getters in Vuex are like computed properties in Vue. And `composition-api` allows us to use `computed` functionality directly. Just import it into our `store.js` file and create a computed function like a `getter` for our store.

```js
// store.js
import { reactive, readonly, computed } from "vue";

const state = reactive({
  keyWord: "good"
});

function changeKeyWord(value) {
  state.keyWord = value;
}

const upperCasedKeyWord = computed(() => state.keyWord.toUpperCase());

export const store = readonly({
  state,
  changeKeyWord,
  upperCasedKeyWord
});
```

#Provide/Inject

We can use `provide` and `inject` to use `store` in all components without importing it in each file.

Just add this to your main component, usually, it's called `App.js`.

```js
// App.js
import { store } from "./store";

export default {
  provide: {
    store
  }
}
```

In our `ComponentA.vue` and `ComponentB.vue` remove import store and just add an `inject`

```vue
// ComponentA.vue & ComponentB.vue
<script>
export default {
  inject: ["store"],
  methods: {
    changeKeyWord(evt) {
      this.store.changeKeyWord(evt.target.value)
    }
  }
}
</script>
```

The Whole complete project of example that is used in this article is in [Sandbox](https://codesandbox.io/s/keen-dew-vh6ms?file=/src/components/ComponentA.vue)

#Conclusion

`Composition API` is a cool feature that can help us in different cases. It's flexible and powerful. But it doesn't mean that you have to replace Vuex with them. It's just a new option. Remember, Vuex is a time-tested plugin in the Vue ecosystem and it has many ready to use solutions. For example, there is an interesting plugin: vuex-history. It implements `undo/redo` functionality. Also, vue dev tools support Vuex. So, think twice about what to use.

Thanks a lot for reading. Please subscribe to my newsletter on this blog and on my youtube channel.

I was inspired by this article on dev.to that is written by Nonso Chukwuogor.

Read full article on my personal blog: https://www.kyle-ocean.dev/composition-api-instead-of-vuex-in-vue3-and-also-vue2