Bad_Pan
Bad_Pan

Reputation: 508

Vue 3 reuse composition API in separate file

I'm new to Vue.js and I'm trying to do the following. I have a working Vue 3 application where I'm testing the composition Api feature. My App.vue file is simple and has the following:

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button @click="increaseCounter()">Increase counter</button>
  </div>
</template>

<script>

import { ref } from "vue";

export default {
  setup() {
    const counter = ref(3);

    function increaseCounter() { 
      counter.value++;
    }
    return { 
      counter, 
      increaseCounter
    };
  }
};
</script>

Now everything is working with this code. What I want to do is to separate the script code into a new separate file and import in the App.vue to reuse it. I tried the following but with no luck:

 <template>
  <div>
    <p> Msg: {{ msg }} </p>
    <p>Counter: {{ counterApi.counter }}</p>
    <button @click="counterApi.increaseCounter()">Increase counter</button>
  </div>
</template>

<script>
  import { counterApi }  from "./counter-api.js";

  export default {
    created: () => {
      counterApi.increaseCounter;
    }
  };
</script>

counter-api.js

 import { ref } from "vue";

export default {
  setup() {
    const counter = ref(3);

    function increaseCounter() { 
      counter.value++;
    }
    return { 
      counter, 
      increaseCounter
    };
  }
};

I'm getting the following error

Cannot read property 'increaseCounter' of undefined.

Thanks in advance

Upvotes: 1

Views: 2773

Answers (1)

chojnicki
chojnicki

Reputation: 3614

You did not showed what is inside counter-api.js. Based on import you have, it should be something like this:

export function CounterApi {
  const counter = ref(3);

  function increaseCounter() { 
    counter.value++;
  }

  return { 
    counter, 
    increaseCounter
  };
}

Or if we use more ES6:

export const CounterApi = () {
  const counter = ref(3);

  const increaseCounter = () { 
    counter.value++;
  }

  return { 
    counter, 
    increaseCounter
  };
}

You imported file, but it's not enough because you did nothing with it. Instead:

<template>
  <div>
    <p>Counter: {{ counter }}</p>
    <button @click="increaseCounter()">Increase counter</button>
  </div>
</template>

<script>
import { CounterApi } from "./counter-api";

export default {
  setup() {
    const { counter, increaseCounter } = CounterApi();
    
    return { 
      counter, 
      increaseCounter
    };
  }
};
</script>

Or

<template>
  <div>
    <p>Counter: {{ someName.counter }}</p>
    <button @click="someName.increaseCounter()">Increase counter</button>
  </div>
</template>

<script>
import { CounterApi } from "./counter-api";

export default {
  setup() {
    const someName = CounterApi(); // use all under single const
    
    return { someName };
  }
};
</script>

There is plenty articles about composition API, for example: https://vueschool.io/articles/vuejs-tutorials/state-management-with-composition-api/

Also it is good idea and common convention to name this composable as useCounterApi and then const counterApi = useCounterApi() or with dectruction const { something, something } = useCounterApi()

It is all in official docs: https://v3.vuejs.org/api/composition-api.html

Upvotes: 1

Related Questions