Home > OS >  How can Vue component functions be made reusable?
How can Vue component functions be made reusable?

Time:04-18

In a Vue application I have many features that can only be used if the user is actively logged in.

The function that checks if the user is authenticated is like this:

    import {useStore} from "vuex";
    import {useRoute, useRouter} from "vue-router";   
        
    export default {
     setup() {
        const VueStore = useStore();
        const VueRouter = useRouter(); 
        const route$ = useRoute();
    
        const isLoggedIn = ref(VueStore.state.securityStore.isLoggedIn);
            
            async function authenticateIdentity() {
                
                  try {
                    await VueStore.dispatch('securityStore/autoLogin');
                    if (isLoggedIn !== true) {
                      return VueRouter.push({name: "Login", query: {redirect: route$.path}})
                    }
                  } catch (error) {
                    return VueRouter.push({name: "Login", query: {redirect: route$.path}})
                  }
                }
             }
         }

The steps are simple:

  1. Ask the VueStore to run an action that logs in the user automatically (using cookies)
  2. If the authentication passed do nothing (that is, let the calling function carry on)
  3. Else if not authenticated, take the user to the Login screen

I would like to keep this code in a separate file and use it in whichever component I need to. How can this be done in Vue3?

CodePudding user response:

You can create a plugin

const myAuthPlugin = {
  install(app, options) {
    // move the Authentication logic and method here
  }
}

app.use(myAuthPlugin)

CodePudding user response:

It is possible to create a Vue3 composable that allows to reuse the function in other places.

The tricky part is the vue-router. We have to make sure that the used router inside the composable is actually the same instance of the router as being used inside the App/components. We cannot use useRouter() which is the method for using the router inside the setup function of components (in our composable we do not have a setup function). Therefore, we suggest to put the router definition in an extra module and share this module between App and composable definitions.

1. Create new file router.js

import {createRouter, createWebHashHistory} from 'vue-router'

const routes = [
    {path: '/', name: 'Home', component: Home},
    {path: '/login', name: 'Login', component: Login},
    ...
    {path: "/:pathMatch(.*)*", component: NotFound},
]

const router = createRouter({
  history: createWebHashHistory(),
  routes: routes
})

export default router;

2. Use router module in main.js

import {createApp} from 'vue'
import router from './router.js'
import App from './components/App.vue'

const myApp = createApp(App);
myApp.use(router)
     .mount('#app');

3. Create composable loggin.js

import {ref} from 'vue';
import store from './store.js';  // assuming this is the file containing the store definition
import router from './router.js';

export async function authenticateIdentity() {
    const isLoggedIn = ref(store.state.securityStore.isLoggedIn);
    try {
        await store.dispatch('securityStore/autoLogin');
        if (isLoggedIn !== true) {
            return router.push({name: "Login", query: {redirect: router.currentRoute.path}})
        }
    } catch (error) {
        return router.push({name: "Login", query: {redirect: router.currentRoute.path}})
    }
}

4. Use composable in other components

<script>
import {authenticateIdentity} from 'loggin.js'

export default {
  name: "LoginComponent",
  methods: {
    login(){
      authenticateIdentity().then( ... ).catch( ... );
    }
  }
}
</script>

(adapt project structure / import paths / names)

  • Related