Tips for accessing a composition function in VueJS from another composition

I've been diving into the new composition-api within VueJS and have encountered a problem that I need help with. I am seeking advice on how to effectively tackle this issue. Previously, when everything was vuex-based, dispatching an action to another module was straightforward. However, I'm facing some challenges with the composition implementation.

Issue:

  1. Component invokes a function from CompositionA.
  2. CompositionA initiates a login function.
  3. Upon successful or failed response from CompositionA's login, I aim to call a function from CompositionB. (CompositionB contains data and logic for displaying a site-wide snackbar)

The challenge lies in having to inject the snackbar dependency into every component rather than having it instantiated/mounted from CompositionA. The current solution is as follows:

Component.vue:

// template calls login(credentials) method
import { useCompositionA } from '@/compositions/compositionA'
import { useCompositionB } from '@/compositions/compositionB'
export default {
  name: 'Component',
  setup(props, context) {
    const { login } = useCompositionA(props, context, useCompositionB(props, context))
    return {
      login
    }
  },
}

compositionA.js:

export const useAuth = (props, context, snack) => {
  const login = async (credentials) => {
    try {
      return await loginWithEmailPassword(credentials)
      snack.show({text: 'Welcome back!'})
    } catch (err) {
      snack.show({text: 'Failed to login'})
    }
  }
  return { login }
}


compositionB.js:

export const useSnack = (props, context) => {
  const snack = reactive({
    color: 'success',
    text: null,
    timeout: 6000,
    visible: true,
  })

  const snackRefs = toRefs(snack)

  const show = ({ text, timeout, color }) => {
    snackRefs.text.value = text
    snackRefs.timeout.value = timeout || 6000
    snackRefs.color.value = color || 'success'
    snackRefs.visible.value = true
  }
  return { 
    ...snackRefs,
    show
  }
}

It would be convenient if something like the following existed, but I'm noticing that the properties are not reactive in CompositionB when used from CompositionA (the method is invoked but the snackbar doesn't appear). My understanding leads me to believe that Vue is not injecting CompositionB into the Component, resulting in another instance of CompositionB running inside CompositionA. Am I missing something here? What's the proper solution?

compositionA.js (not working):

import { useCompositionB } from '@/compositions/compositionB'
export const useAuth = (props, context) => {
  const login = async (credentials) => {
    const { show } = useCompositionB()
    try {
      return await loginWithEmailPassword(credentials)
      show({text: 'Welcome back!'})
    } catch (err) {
      show({text: 'Failed to login'})
    }
  }
  return { login }
}

Appreciate your insights,

Answer №1

It was no surprise that the issue stemmed from the Component referencing its own local version of CompositionB*. The solution, in fact, lies in bringing the state of your compositions into the global scope as shown below:

Visit this link for more details on Vue.js Composition API usage.

You can implement something similar to the following code snippet:

compositionB.js:

const snack = reactive({
  color: 'success',
  text: null,
  timeout: 6000,
  visible: true,
})
export const useSnack = (props, context) => {

  const snackRefs = toRefs(snack)

  const show = ({ text, timeout, color }) => {
    snackRefs.text.value = text
    snackRefs.timeout.value = timeout || 6000
    snackRefs.color.value = color || 'success'
    snackRefs.visible.value = true
  }
  return { 
    ...snackRefs,
    show
  }
}

This method works seamlessly.

The only minor issue encountered initially was a composition-api error message:

Uncaught Error: [vue-composition-api] must call Vue.use(plugin) before using any function.

To resolve this, simply ensure that you mount the composition-api first thing in main.js as detailed in the solution provided here:

Resolve the Uncaught Error related to vue-composition-api

I anticipate that this issue will not persist once vue3 is released. Hopefully, this explanation proves helpful to someone facing a similar challenge.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Add the file to the current directory

As a newer Angular developer, I am embarking on the task of creating a web page that enables users to upload files, with the intention of storing them in a specific folder within the working directory. The current location of the upload page component is ...

Ways to manage numerous AJAX actions within a single HTTP request?

Currently, I am utilizing jQuery to create a multipart web page containing a list of links that are updated through periodic AJAX HTTP requests. Each link on the page is triggered by a timer in JavaScript, causing it to make an HTTP request to its designat ...

The TypeScript compiler generates a blank JavaScript file within the WebStorm IDE

My introduction to TypeScript was an interesting experience. I decided to convert a simple JavaScript application, consisting of two files, into TypeScript. The first file, accounts.ts, contains the main code, while the second one, fiat.ts, is a support f ...

Explore a personalized color scheme within MUI themes to enhance your design

I'm looking to customize the colors in my theme for specific categories within my application. I set up a theme and am utilizing it in my component like this: theme.tsx import { createTheme, Theme } from '@mui/material/styles' import { red ...

Populate an array with the present date and proceed in reverse order

In my code, there is an array that has a specific structure: var graphData = [{ data: [[1, 1300],[2, 1600], [3, 1900], [4, 2100], [5, 2500], [6, 2200], [7, 1800]} I want to replace the numbers in the first element of each sub-array with the corresponding ...

Experiencing issues with implementing shopping cart logic using KnockoutJS. Need help

The Objective Create a dynamic list of products. The Scenario Overview In my online shopping application, I want to showcase the products I add to my shopping list in a sidebar when I click the 'add button' for each product. Brief Problem Sum ...

Using JavaScript to set attribute values in Python Selenium, these values are cleared after each update

Assuming : for i in list('{}'.format(value)): self.browser.execute_script( "arguments[0].setAttribute('value', '{}');".format(i.replace('&b ...

Retrieve data from Last.fm API by utilizing both Node.js and Angular framework

I am currently working on implementing the node-lastfmapi track.search method into my project. I have successfully retrieved the results, but I am facing challenges in integrating them into the front end using Angular. My backend is powered by mongoDB and ...

Steps to show the chosen index value in an alert pop-up using Ionic 2 framework

I'm in the process of trying to showcase a selected index value within an Ionic 2 alert box. However, I'm struggling to find the correct method to display it in the Ionic prompt. This pertains to the home.ts import { Component } from '@ang ...

Tips for utilizing the /foo-:bar pathway in Nuxt.js?

I am trying to utilize the router /foo-:bar in Nuxt. Do you have any suggestions on how I could make this work? I attempted using pages/foo-_bar.vue but it did not yield the desired results. ...

Enhancing nouislider jQuery slider with tick marks

I have integrated the noUIslider plugin () into one of my projects. I am seeking guidance on how to display tick marks below each value on the slider. This is the current initialization code for the slider: $slider.noUiSlider({ 'start': sta ...

Using recursive setTimeout in Javascript may not always utilize the entire final JSON object that is returned

My current approach involves making recursive calls to a URL until it returns either a success or reaches the maximum limit of tries. Below is a compact version of the relevant code: function doSomething(numRetries) { $.post('someURL', {retr ...

Access the value of a submitted form using jQuery, when there are multiple forms with identical class names

I've looked for a solution here but couldn't find one that meets my needs. I have multiple forms with the class name .sbt-form: <form class='sbt-form'> <input name='kord' val=1/> </form> <form class= ...

Dynamically populating checkboxes and dynamically setting their checked state

I'm working with a for loop that dynamically generates 7 checkboxes in a row. Here's how it looks: @for (int i = 1; k < order.Rows.length; i++) { Row: @i <ul> @for (int j = 1; j < order.NumCheckboxes.length; j++) ...

Using Twitter bootstrap with Node.js and Express framework

Is it possible to integrate Twitter Bootstrap with Node.js and Express? I understand that I need to place CSS and Javascript files in the ./public directory (if it's set as default). However, when trying to implement Twitter Bootstrap on Node.js and ...

Using jQuery's sortable functionality to rearrange rows in a table can cause conflicts with Angular's orderBy feature

In the past, my angular app used a table with orderBy to sort rows based on a specific column. By clicking on a table header, the orderBy arguments would change and the list would be sorted according to the values in that column. Now, I am experimenting w ...

Remove any errors as soon as the input field becomes valid

My current setup involves AngularJS with node.js. To handle errors, I have devised the following strategy: node router effect.js: router.post('/', function(req, res, next){ req.checkBody('name', 'Eff ...

Attempting to conceal the API, however, the backend is throwing an error

view the error image I am currently in the process of developing an NFT search application that is capable of locating the NFTs associated with a specific wallet address. However, I am faced with the challenge of using Alchemy without exposing the API key ...

Using Typescript to create an asynchronous function without explicitly declaring a Promise

When you examine TypeScript's async function, you may notice the redundancy with "async" and "Promise<type>". public async test(): Promise<string> { return "Test"; } Is there a way to configure TypeScript to handle async types ...

Encountering issues with Node.js and Socket.io not displaying results on Internet Explorer when using a secure connection

I have successfully integrated socket.io, node.js, and express to serve real-time json data to multiple browsers except for IE (tested on version 9) over a secure connection. Everything was functioning smoothly until I switched to HTTPS. From the server&ap ...