Utilizing setInterval in Vue 3 to efficiently eliminate elements from an array

I am looking to implement a straightforward Snackbar using VUE 3. While I had no trouble doing this in Vue 2, Vue 3 seems to have some nuances.

Currently, I have stored the messages array in the Vuex store as shown below:

import { createStore } from 'vuex'

export default createStore({
  state: {
    snackbarText: []
  },
  mutations: {
    DELETE_SNACKBAR_MESSAGE(state) {
      state.snackbarBarText.shift()
    },
    ADD_SNACKBAR_MESSAGE(state, message) {
      state.snackbarBarText.push(message)
    }
  },
  getters: {
    MESSAGES: (state) => state.snackbarText
  }
})

This is what my Snackbar.vue component looks like at the moment:

import { useStore } from 'vuex';
import { ref, watch} from 'vue';

export default {
  set() {
    const store = useStore();
    const text = ref(store.getters["MESSAGES"]);
    
    if (text.value.length) {
      let timer = setInterval(() => {
        store.commit('DELETE_SNACKBAR_MESSAGE');
        
        if (text.value.length) {
          clearInterval(timer)
        }
      }, 3000)
    }    

    return { text }
  }
}

I am trying to figure out how to check the length of the text ref in the Snackbar and trigger a timer function. My challenge lies in implementing this logic in Vue 3's Composition API, which I'm still getting acquainted with.

The expected behavior is for messages to be added to the array and displayed to the user. After 3 seconds, they should be removed from the array. I find using watch cumbersome and struggle with restarting setInterval after it has been stopped.

Any guidance on this issue would be highly appreciated!

Answer №1

After revising my previous response that relied on the usage of setInterval, it became apparent that this method is not suitable for the specific functionality required. The seamless transition between elements poses a challenge in this context.

In Vue2, one might opt for utilizing the EventBus to monitor any modifications within the snackbar message array. However, with the absence of this feature in Vue3, one could persist with an EventBus-like module or leverage subscribe.

The provided code snippet encapsulates the entire component:

<template>
  <transition name="component-fade" @after-leave="checkForMoreSnacks">
    <div class="snackbar" v-if="currentSnack">
      <div class="snackbar__container">
        <p>{{ currentSnack }}</p>
        <button @click="closeCurrentSnack">Close Me</button>
      </div>
    </div>
  </transition>
</template>

<script>
import { useStore } from "vuex";
import { computed, ref } from "vue";
export default {
  setup() {
    const timerInterval = 1500;
    const store = useStore();
    let timeoutToken = null;
    let snacks = computed(() => store.getters["GET_SNACKBAR_MESSAGES"]);
    let currentSnack = ref(null);

    // Triggered event that initiates the showing of Snackbar,
    // akin to emitting an event via EventBus
    store.subscribe(mutation => {
      // Listening for a specific mutation call
      if (mutation.type === "ADD_SNACKBAR_MESSAGE") {
        // Do not proceed if there already is a displayed snack
        if (currentSnack.value) return;

        // Assigns value to 'currentSnack' from the first index of 'snacks' array and removes that item from the store
        currentSnack.value = snacks.value[0];
        timeoutToken = setTimeout(() => {
          closeCurrentSnack();
        }, timerInterval);
      }
    });

    function closeCurrentSnack() {
      store.commit("DELETE_SNACKBAR_MESSAGE");
      currentSnack.value = null;
      timeoutToken = null;
    }

    function checkForMoreSnacks() {
      if (!snacks.value.length) {
        timeoutToken = null;
        currentSnack.value = null;
      } else {
        currentSnack.value = snacks.value[0];
        timeoutToken = setTimeout(() => {
          closeCurrentSnack();
        }, timerInterval);
      }
    }

    return {
      currentSnack,
      checkForMoreSnacks,
      closeCurrentSnack
    };
  }
};
</script>

<style lang="scss" scoped>
.snackbar {
  position: absolute;
  right: 10px;
  bottom: 10px;
  max-width: 500px;
  border: solid 2px red;
  padding: 1rem;
  border-radius: 5px;

  &__container {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 30px;
  }
}

.component-fade-enter-active,
.component-fade-leave-active {
  transition: opacity 0.3s ease;
}

.component-fade-enter-from,
.component-fade-leave-to {
  opacity: 0;
}
</style>

The crucial aspect here lies in the utilization of the @after-leave hook. It was observed that upon removing the displayed snackbar, further checks can be performed using this hook.

This same hook was also the reason for steering clear of employing setInterval.

A Git repository for this implementation has been established at this link.

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

Error code 1 encountered an internal error while trying to execute a task

Currently, I have this job set up to clear out unnecessary records. The code provided has been simplified for debugging purposes. However, almost 80% of the time when running it, it fails to find anything due to Error code 1 "internal error": Parse.Cloud. ...

Unusual behavior exhibited by JavaScript's eval() function

As part of my website design, I am developing custom Message Boxes that can display normal OK dialogs as well as Yes/No dialogs. These popups prompt the user to click either "OK" or "Yes/No", which then triggers corresponding callbacks executed using eval( ...

Issue with server-side rendering due to importing routes

After researching SSR with React, I came across various approaches but found one example that seems more suitable for my web app built on React/GraphQL/Apollo/Express/Webpack. However, I am facing an issue. Here are some code snippets: server.js ... ...

What is the best way to locate a specific item within an array of objects, especially when each object has the potential to contain an array of objects of the

I am grappling with the challenge of finding a specific object within an array of objects, where the desired object may be nested within another array of one of the objects. I have experimented with various iterations of forEach loops and recursion method ...

Using the `find()` method in a loop of Mongoose iterate

Searching for documents based on conditions stored in an array can be quite useful. Take this example: subscriptions=[ {teacher: 'john', student:'david' ,course:'math'}, {teacher: 'john', student:'david' , ...

Synchronizing client information in real-time: tips, tricks, and expert advice

Currently, I am developing a PHP backend and utilizing JS/Jquery for the front end of an application that aims to facilitate near real-time communication among users. My main concern right now is determining the most effective approach to achieve this goal ...

Ionic 2: Inconsistency detected in the expression after it was verified

After going through this response, this solution and this advice (as well as numerous others), I still find myself struggling to comprehend how to resolve this issue in my current approach. The task at hand involves creating an event countdown timer that ...

AngularJS Firebase Login Scope Value Not Retained After Refresh

I have stored my unique username in the variable "$scope" and I am trying to access it from different views once the user logs in, using: However, when I refresh the page immediately after the user successfully signs in, the value of "$scope" goes bac ...

Utilizing the "each" function in jQuery to create click events for buttons that are linked to specific paragraphs

Right now, I am facing a situation where I have three buttons, each assigned with an ID that matches their order. Upon clicking a button, the paragraph associated with that order should hide itself using .hide(). My challenge lies in finding out how to ut ...

The function Slice() does not function properly when used with two-dimensional arrays

I have been attempting to duplicate a 2D array by value using the slice() method in order to prevent any changes made to the new array from impacting the original. Oddly enough, it seems that this approach is effective with a 1-dimensional array but not wi ...

In Javascript, swap out a particular colored region in an image with a different image

I've been scouring the internet in search of a solution to my problem, but it seems like I might not be looking in the right places. Imagine this image below, how can I replace the blue area with an image uploaded by the user? I'm struggling to ...

Methods to constrain click event handling between parent and child elements in Vue.js

I am currently in the process of converting a semantic-ui component to rely on Vue.js rather than jQuery. However, I am facing an issue with isolating v-on:click between a child and its parent element. In the example below, I have a button that uses v-on: ...

Can SVG use a transformation matrix to switch the values of x and y coordinates?

Currently using the svgpath library to manipulate SVGs, I am looking for a way to alter the coordinate system so that the y-axis becomes the x-axis and the x-axis becomes the y-axis. Is there any method to achieve this? I have attempted to rotate around ...

Exploring the capabilities of the Scripting.FileSystemObject within the Microsoft Edge browser

With the removal of ActiveXObject in Microsoft Edge, what is the alternative method to use FileSystemObject in this browser? I am currently working on developing a Microsoft Edge plugin that captures the HTML code of a web page and saves it as a .txt fil ...

Fetching a JSON object from an external URL using JavaScript

Currently, I am working on a project using JavaScript and have an API that provides me with a JSON Object. You can access this JSON object by clicking on the following link: . Within this JSON object, there is a specific element located at JSONOBJECT.posi ...

Is there a way to modify the existing JSON format?

After receiving a JSON response, I used the code snippet result = JSON.parse(result.value); to parse it. The JSON response I received was: {"name":"For ","children":["{ \"name\":\"sxsm cnklsd\"}","{ \"name\":\"smd csdm&b ...

Passport.authenticate() fails to redirect users to the desired destination

I am encountering an issue with the passport middleware while trying to authenticate a user. The redirection doesn't seem to be working and I'm unsure what the problem is. Here is the code snippet from the project, and the complete project is av ...

Content not being displayed by Javascript

I'm having trouble displaying content using JavaScript DOM. Every time I try to run my code, the page comes up blank. Here is an example of my HTML file: <!DOCTYPE html> <html> <head> <title>Radiant HQ</titl ...

What is the best way to center an infowindow in Google Maps API V3 when working with a map canvas that has a narrow width?

As an illustration of my point, I have put together a sample page: The issue I am facing is with a narrow map canvas and an infowindow in it. Upon clicking the marker, the map sometimes fails to center properly and the marker along with the infowindow sli ...

Error message: Unable to split path as a function when utilizing React hook forms in conjunction with Material UI

Check out this code snippet: <TextField name="name" required className='my-2 mx-auto' label="Full Name" variant="standard" style={{ "width": "60%" }} value={name} onChange={(event) => { set ...