Must-Know Reusable Module Vs Component In Vue 3 Composition API
Published: 2021-07-26 11:53:35

As a Vue.js developer, we want to keep our code *clean* and *tidy* by creating the optimal amount of reusable code.

In Vue 3 with the [Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html), we can absolutely do that by creating reusable JS **modules** aka **hook functions** and **child components**.

*So what’s the difference between them?*

*When do we use one or the other?*

Let’s find out!

**JavaScript module** aka **hook function** is a great way to separate business logic from the Vue component.

It’s completely reusable and UI independent.

If you’re coming from MVC pattern, this would be M (Model) part of it.

**Vue components** that are not page-based, meaning no route attached to it, aka Child components, are great when we want to reuse HTML template code aka UI that can be used in multiple parent components.

Now you have a better understanding of not only the differences, but also which one to use when.

I’m going to demonstrate with some example code throughout this article to show cases of when to use them.

>*Note: This article is intermediate and you should have the basic knowledge of using [Vue.js](https://softauthor.com/category/vue-js/) or a similar framework.*

###Get A List Of Products

I assume you already know how to get [Up and Running With Vue JS 3 Project Using Vue CLI](https://softauthor.com/up-and-running-with-vuejs3-project/).

Let’s say we have a **ProductList.vue** page-based component in our application handling async operation to get a list of products.

I used Firebase in the example below for the async operations.

>*I have an article on [how to install Firebase to your vue project](https://softauthor.com/add-firebase-to-vuejs/) as well as on how to make [Cloud Firestore queries](https://softauthor.com/firestore-querying-filtering-data-for-web/) if you’re interested.*

First, create a product reactive array and call **loadProduct()** function inside **onMounted()** lifecycle method.

>Recommended
>[*Must-Know Ref vs Reactive Differences In Vue 3 Composition API*](https://softauthor.com/vue3-ref-vs-reactive/)

```JavaScript
import firebase from "firebase";
import { onMounted, reactive } from "vue";
export default {

  setup() {

    const products = reactive([]);

    onMounted(() => {
      loadProducts();
    });

    const loadProducts = async () {
      try {
        const productsSnap = await firebase
          .firestore()
          .collection("products")
          .orderBy("brand", "asc")
          .get();

        productsSnap.forEach((doc) => {
          let product = doc.data();
          product.id = doc.id;
          products.push(product);
        });

      } catch (e) {
        console.log("Error Loading Products");
      }
    }

    return {
      products,
    };
  },
};
```

Inside the **loadProducts()** declaration, use Firebase query to get a list of products that I’ve already stored in the [Firebase Cloud Firestore database](https://softauthor.com/vue-firebase-structure-model-cloud-firestore/).

Finally return the products array to use in the template.

Each product object has two keys that are:
- title
- upc

Nothing fancy.

This works great!

As the project evolves, let’s say I’ll need to create an inventory component where I want to use a list of products as a drop-down, for example, to select a product to create an inventory from.

I’ll have to rewrite **loadProducts()** code which I do not want to do.

With [Vue 3 Composition API](https://v3.vuejs.org/guide/composition-api-introduction.html), we can easily extract the async code into a UI-independent JavaScript module and can reuse it wherever we want in our application.

Let’s see how to do that.

###Reusable Product.js Module

Create a **Product.js** file inside the **src/modules** folder which is where all of my product-related async operations will go such as *loadProducts*, *addProduct*, *updateProduct*, *deleteProduct*, etc.

Let’s see how to extract the **loadProducts()** code from the **ProductList.vue** to **Product.js**.

Import [Firebase](https://softauthor.com/category/firebase/) as we’ll be using it for CRUD async operations.

Then declare **useProduct()** function as well as reactive state object inside the function which will have one property in it called products that is a type of array.

```JavaScript
import { reactive, toRefs } from "vue";
import firebase from "firebase";

export default function useProduct() {
  const state = reactive({
    products: [],
  });

  const loadProducts = async() => {
    try {
      const productsSnap = await firebase.firestore().collection("products").orderBy("brand", "asc").get();
      productsSnap.forEach(doc => {
        let product = doc.data();
        product.id = doc.id;
        state.products.push(product);
      });
    } catch (e) {
      console.log("Error Loading Products")
    }
  }
  return { ...toRefs(state),
    loadProducts
  }
}
```

Then, create the **loadProducts()** function which gets the products data from the products collection in [Cloud Firestore](https://softauthor.com/firestore-querying-filtering-data-for-web/) and gets the snapshot of it.

Loop through them and push each product into the products array.

Finally, return the state and loadProduct.

The reason I wrapped state with **toRefs** is to convert the reactive object into a plain JavaScript object so that I can *destructure* it when needed.

Now we have the **Product.js** module ready to use inside the **ProductList.vue** or any component that needs a list of products in our app.

###ProductList.vue

Now, we can easily get a list of products like before with just four steps.

First, import the product module at the top.

Secondly, call **useProduct()** function and destructure **products** and **loadProducts** inside the **setup()** function.

Then, invoke loadProducts() inside the onMounted() lifecycle method.

```JavaScript
import { onMounted } from "vue";
import useProduct from "@/modules/product";
export default {
  setup() {
    const { products, loadProducts } = useProduct();
    onMounted(async () => {
      await loadProducts();
    });
    return {
      products,
    };
  },
};
```

Finally, return the products which is the same as before.

At this stage, products are available in the template to use and we can loop through them using v-for to show however we want.

>Recommended
>[*Vue + Firestore ← Build A Simple CRUD App with Authentication*](https://softauthor.com/vue-firestore-crud-app-authentication/)

You can see how easy it is to create a module like Product.js to organize reusable UI-independent functionalities. 🙂

One more benefit of using modules like **Product.js** is to use them as state management as well.

###Modules As State Management

To use modules as state management, all we need to do is to declare the **state** object model outside of the **useProduct()** function which then becomes a global variable.

```JavaScript
import { reactive, toRefs } from "vue";
import firebase from "firebase";

 const state = reactive({
        products: [],
 });

export default function useProduct() {
  ...
}
```

[Continue Reading...](https://softauthor.com/vuejs-composition-api-reusable-module-vs-component/)