A guide on integrating a vue-concurrency Task Creator with argument support

I've been grappling with my Vue 3 / TypeScript app and the vue-concurrency library.

Everything is nearly in place, but configuring a Task Creator to accept arguments has proven to be quite challenging.

Following the Task Creators pattern outlined in the documentation, here's an example:

src/composables/tasks.ts

/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { timeout, useTask } from 'vue-concurrency';

export const useReturnTextTask = (text: string) => {
  return useTask(function* () {
    // Simulate an API call that takes a string argument and returns a string
    yield timeout(1000);
    return text;
  });
};

Within a component, it's implemented like this:

src/components/example.vue

<template>
  <input v-model="textInput" type="text" />
  <button @click="handleClick">Click to Perform Task</button>
  <div v-if="returnTextTask.last?.isError">
    {{ returnTextTask.last?.error.message }}
  </div>
  <div v-else>
    {{ returnTextTask.last?.value }}
  </div>
</template>

<script setup lang="ts">
/* eslint-disable @typescript-eslint-no-unsafe-member-access */
/* eslint-disable @typescript-eslint-no-unsafe-assignment */
/* eslint-disable @typescript-eslint-no-unsafe-call */
import { useReturnTextTask } from 'src/composables/test';
import { ref } from 'vue';

const textInput = ref<string>();

const handleClick = async () => {
  if (textInput.value) {
    const returnTextTask = useReturnTextTask(textInput.value);
    const returnTextInstance = returnTextTask.perform();
    await returnTextInstance;
    if (returnTextTask.last?.isSuccessful) {
      console.log(returnTextTask.last?.value);
      console.log(returnTextInstance.value);
    }
  }
};
</script>

The issue arises because useReturnTextTask requires a text argument, so I utilized it within if (textInput.value).

However, using it that way results in all references to returnTextTask in the template throwing the error

Cannot find name 'returnTextTask'. ts(2304)
.

This seems to be due to the fact that returnTextTask may not always be defined when nested inside if (textInput.value).

How can I resolve this challenge?

I also attempted declaring returnTextTask outside of handleClick, such as

let returnTextTask: Task<string, []>;
, however, this led to runtime errors as it was declared with an undefined value (
TypeError: Cannot read properties of undefined (reading 'last')
).

Answer №1

I managed to resolve this issue by implementing refs and incorporating a check for undefined in the Task generator function. Here's how I did it:

/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { Ref } from 'vue';
import { timeout, useTask } from 'vue-concurrency';

export const useReturnTextTask = (text: Ref<string | undefined>) => {
  return useTask(function* () {
    if (text.value) {
      console.log('inside Task', text);
      yield timeout(1000);
      return text;
    } else {
      throw new Error('Text required.');
    }
  });
};

To improve functionality, I moved the useReturnTextTask() function to the top level like so:

<template>
  <input v-model="textInput" type="text" />
  <button @click="handleClick">Click to Perform Task</button>
  <div v-if="returnTextTask.last?.isError">
    {{ returnTextTask.last?.error.message }}
  </div>
  <div v-else>
    {{ returnTextTask.last?.value }}
  </div>
</template>

<script setup lang="ts">
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-call */
import { useReturnTextTask } from 'src/composables/test';
import { ref } from 'vue';

const textInput = ref<string>();

const returnTextTask = useReturnTextTask(textInput);

const handleClick = async () => {
  const returnTextInstance = returnTextTask.perform();
  await returnTextInstance;
  if (returnTextTask.last?.isSuccessful) {
    console.log('returnTextTask.last?.value', returnTextTask.last?.value);
    console.log('returnTextInstance.value', returnTextInstance.value);
  }
};
</script>

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

What is a way to execute a series of requests using rxjs similar to forkJoin and combineLatest, without needing to wait for all requests to finish before viewing the results?

Consider you have a list of web addresses: urls: string[] You create a set of requests (in this instance, utilizing Angular's HTTPClient.get which gives back an Observable) const requests = urls.map((url, index) => this.http.get<Film>(url) ...

Angular has got us covered with its latest feature - combining Async Await with an EventListener

I have been facing this issue for the past day and need help creating a specific scenario: <img [src]="userdp | async" /> In my component.ts file, I want to include only this line: this.userdp = this._userService.getUserDp(); Here is the ...

Utilizing Angular 11's HostListener to capture click events and retrieve the value of an object

Using the HostListener directive, I am listening for the click event on elements of the DOM. @HostListener('click', ['$event.target']) onClick(e) { console.log("event", e) } Upon clicking a button tag, the "e" object contains the fol ...

Combining Promises in Typescript to create a single Promise

Is there a way for me to return the temp_data object filled with data after using .map? Currently, it always returns undefined because I initialize temp_data as an empty object. But if I don't do this, I can't use LooseObject. Can anyone suggest ...

Encountering parameter issues while working with Google Maps React in TypeScript

Currently, I'm utilizing TypeScript in this particular file. import React, {Component} from 'react' import {Map, InfoWindow, Marker, GoogleApiWrapper, mapEventHandler, markerEventHandler} from 'google-maps-react'; import { coordina ...

Has an official Typescript declaration file been created for fabric.js?

Currently, I have come across a Typescript definition for fabric.js on https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/fabric (https://www.npmjs.com/package/@types/fabric). However, its official status is unclear. Does anyone have more ...

During the rendering process, the property "projects" was attempted to be accessed, however, it has not been defined within

I am struggling to understand this issue. Despite looking at numerous other problems and solutions, I still can't grasp the root cause of the error. In my projects.js file, there is an array. Whenever I try to import {projects} from "@/projects.js", I ...

What is the best way to maintain the previous input value on page refresh in Vuejs?

In my development project, I am utilizing the Laravel and Vue.js technologies. I am facing an issue where I need to set the input value to its previous old value when either refreshing the page or navigating back to it in a Vue dynamic component. Here is ...

Exploring TypeScript: A Study on Interfaces and Abstraction

I am working with TypeScript and have created four different entities (models) as shown below: Base model definition: export interface BaseModel { id: string; entityId: string; entityName: string; } Child Model 1: import { BaseModel } from ' ...

Unable to successfully remove item using Asyncstorage

const deleteProduct = prod => { Alert.alert( 'Delete Product', `Are you sure you want to remove ${prod.id}?`, [ { text: 'Cancel', style: 'cancel', }, { ...

Utilizing v-model for dynamic binding within a v-for iteration

I'm currently working on binding v-model dynamically to an object property within an array of objects. I am unsure about how to accomplish this task. The objective is to choose a user using the Select HTML tag and then display the list of that user&ap ...

Create a new function within the GraphQL Resolvers file

I am trying to define a function within the same ts file as where I specify the resolvers export const resolvers = { Query: { books: () => { return [ { title: 'Harry Potter and the Chambe ...

The route parameters in Vue SSR are being retrieved from a separate request

I am currently using Akryum/vue-cli-plugin-ssr along with vue-cli, but I have encountered an unusual issue in my Vue SSR application. It seems that the route params are getting mixed up with requests made either before or in parallel to the current one. F ...

What's preventing me from using just one comparison condition in TypeScript?

The issue at hand is quite simple: An error occurred because I tried to compare a number with a 'Ref<number>' object. It seems ridiculous that I can't compare two numbers, but as I am new to Typescript, I would greatly appreciate some ...

Custom Mui table sizes - personalized theme

By implementing custom sizes for the Table component in Material UI, I have extended the Table size prop with the following declaration: declare module '@mui/material' { interface TablePropsSizeOverrides { relaxed: true large: true } ...

The limitations of Chrome preventing it from setting cookies

After receiving a response from my server, I found that the Response Headers contain a valid Set-Cookie. When checking Chrome Response/Cookies, it shows that there is 1 cookie present. However, when inspecting DevTools/Application/Cookies, the cookie is no ...

Choose a specific location on a vehicle illustration within a pop-up window. The image should be partitioned into 6 separate sections

I have a project for my client where they need to choose a car and then indicate where the damage is located on an image, which is divided into 6 sections. I'm struggling to figure out how to achieve this. I initially thought z-index would work, but ...

Determine the full location information with the help of Google Maps SDK without the need

My current challenge involves dealing with a list of unformatted and incorrectly written addresses. I am seeking a way to iterate through these flawed strings and generate more organized and accurate addresses using one of the many Google Maps SDKs availa ...

Issue with Vue class binding failing to update when state is modified

I'm attempting to utilize Vue class binding depending on the index within the v-for loop. While I can see that the state in Vue dev tools is changing correctly, the class name itself isn't being updated. <div class="group" v-for= ...

Dynamic data series updates in Vue ApexCharts

Is there a way to dynamically update data in an ApexCharts series? I have developed a Vue Component utilizing ApexCharts. This component receives updates from its parent where multiple instances are present. The updated values are passed through props. < ...