Courses

Vue.js 3 + Laravel 11 API + Vite: SPA CRUD

Load Data with Vue 3 Composition API

Summary of this lesson:
- Converting to Vue 3 Composition API syntax
- Creating reusable composables
- Setting up path aliases for imports
- Implementing script setup syntax

Vue.js version 3 introduced a new way of writing Vue components called Composition API. Since version 3.2 Vue.js release <script setup> as a new way for writing Vue components. In this lesson, we will combine <script setup> with the composables to write reusable code.


First, let's create a composable. Create a new file resources/js/composables/posts.js and put code inside.

resources/js/composables/posts.js:

import { ref } from 'vue'
 
export default function usePosts() {
const posts = ref([])
}

In this composable first, we import the ref. Ref means reference which will make posts variable reactive.

Then as in every file, we need to export default. In our case, we will export the result of the function usePosts. Such useXyz() is the default naming convention name that starts with the use.

Next, we need to add an async method for getting the posts.

resources/js/composables/posts.js:

import { ref } from 'vue'
 
export default function usePosts() {
const posts = ref([])
 
const getPosts = async () => {
axios.get('/api/posts')
.then(response => {
posts.value = response.data;
})
}
}

And all the exposed states need to be returned. Now we have posts and getPosts.

resources/js/composables/posts.js:

import { ref } from 'vue'
 
export default function usePosts() {
const posts = ref([])
 
const getPosts = async () => {
axios.get('/api/posts')
.then(response => {
posts.value = response.data;
})
}
 
return { posts, getPosts }
}

Now we need to change the Vue component. Instead of <script> use <script setup> and use just created composable.

resources/js/components/Posts/Index.vue:

<template>
// ...
</template>
 
<script setup>
import { onMounted } from "vue";
import usePosts from "../../composables/posts";
 
const { posts, getPosts } = usePosts()
onMounted(() => {
getPosts()
})
</script>
<script>
export default {
data() {
return {
posts: []
}
},
mounted() {
this.fetchPosts()
},
methods: {
fetchPosts() {
axios.get('/api/posts')
.then(response => this.posts = response.data)
.catch(error => console.log(error))
}
}
}
</script>

As you can see, this way we need to write less code in the Vue component itself, and also everything in the composable can be reused in other components.

In other words, composable is an equivalent of Service class in PHP/Laravel, and Vue component is using the Service method, like a Laravel Controller.


Removing "../../"

We can improve importing files instead of going back directories with dots like ../../ we can change it to the @ sign.

To do this, we need to add a new alias to the vite config.

vite.config.js:

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
 
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
'@': '/resources/js',
},
},
});

Now we can import like this:

resources/js/components/Posts/Index.vue:

import usePosts from "../../composables/posts";
import usePosts from "@/composables/posts";

One more tip here. Importing files this way your IDE might complain. But we can easily fix it by creating a file jsconfig.json with the code:

jsconfig.json:

{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["resources/js/*"]
}
},
"exclude": ["node_modules", "public"]
}

In the next lessons, I will be using the <script setup> syntax and will be importing with the @ alias.

Previous: Table Data from API: v-for and axios.get()
avatar

Hello. Not sure where I should put the jsconfig.json file. Should it be at resources/js or root laravel folder? Tried both but didnt work. I'm using nvim so it might be the problem

avatar

If it isn't written in any directory then it's root. But yes I think it's your editors problem. Might need some plugin to

avatar
You can use Markdown
avatar
You can use Markdown