New techniques in VueJS 3: managing value changes without using watchers

I am currently working on coding a table with pagination components and I have implemented multiple v-models along with the use of watch on these variables to fetch data. Whenever the perPage value is updated, I need to reset the page value to 1. However, this results in the watch method being triggered twice - once for perPage and then again for page.

Is there a way to update a variable without triggering the watch at that specific moment?

Below is my current code snippet:


<script setup lang="ts">

const sort = ref(route.query.sort || 'created_at')
const filters = ref(route.query.filters || {})
const page = ref(route.query.page ? parseInt(route.query.page.toString()) : 1)
const perPage = ref(route.query.per_page ? parseInt(route.query.per_page.toString()) : 10)

watch([sort, filters, page, perPage], ([oldSort, oldFilters, oldPage, oldPerPage], [newSort, newFilters, newPage, newPerPage]) => {
  if (oldPerPage !== newPerPage)
    page.value = 1

  fetchItems()

  router.push({
    query: {
      ...route.query,
      sort: sort.value,
      // filters: filters.value,
      page: page.value,
      per_page: perPage.value,
    },
  })
})

async function fetchItems() {
  items.value = await userApi.list({
    filters: toRaw(filters.value),
    sort: sort.value,
    page: page.value,
    perPage: perPage.value,
  })
}
</script>

<template>
    <CTable
      :pagination-enabled="true"
      v-model:sort="sort"
      v-model:page="page"
      v-model:per-page="perPage"
      :total-items="items.meta.total"
      :total-pages="items.meta.last_page"
    />
</template>

The only workaround I found is to add a return statement when resetting the page value:

watch(..., () => {
  if (oldPerPage !== newPerPage) {
    page.value = 1
    return
  }

  fetchItems()

  ...
})

This solution works for my case, but I would prefer a method to update the variable without triggering the watch method for other situations as well.

Thank you!

Answer №1

Set up a new observer for the perPage parameter:

watch([sort, filters, page, perPage], ([oldSort, oldFilters, oldPage, oldPerPage], [newSort, newFilters, newPage, newPerPage]) => {

  fetchItems()

  router.push({
    query: {
      ...route.query,
      sort: sort.value,
      // filters: filters.value,
      page: page.value,
      per_page: perPage.value,
    },
  })
})

watch(perPage, (newPerPage,oldPerPage ) => {
  if (oldPerPage !== newPerPage)
    page.value = 1
})

To improve efficiency and reduce conflicts, it's advisable to monitor each property separately. For the initial observer, consider using watchEffect instead since you don't require the comparison between old and new values:

watchEffect(() => {
  fetchItems()
  router.push({
      query: {
        ...route.query,
        sort: sort.value,
        // filters: filters.value,
        page: page.value,
        per_page: perPage.value,
      },
  })
})

Answer №2

Thanks to everyone for your help! I finally discovered the solution I was searching for by utilizing VueUse - watchIgnorable:

const { stop, ignoreUpdates } = watchIgnorable(page, (value) => {
  fetchItems()
})

watch(perPage, (newPerPage, oldPerPage) => {
  if (newPerPage !== oldPerPage) {
    ignoreUpdates(() => {
      page.value = 1
    })
  }

  fetchItems()
})

Answer №3

When using v-model to change the state, it's important to keep an eye on it with a watcher.

To prevent multiple triggers of the watcher, additional conditions should be implemented as shown in the previous code snippet. However, it is crucial not to skip an update when the page is already set to 1, as this won't lead to any extra updates:

  if (oldPerPage !== newPerPage) {
    page.value = 1

    if (newPage !== 1)
      return
  }

If there are other factors at play aside from perPage that may trigger the watcher causing asynchronous side effects (such as fetchItems), it's best to debounce it to ensure it only runs when necessary. Here is an example:

watch(perPage, () => {
  page.value = 1
});

watch([sort, filters, page, perPage], debounce(() => {
  fetchItems()
  ...
}, 100));

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

The JavaScript file fails to load when accessing port 8080

As I embark on my journey into backend development, please bear with me. Currently, I am working on a JavaScript program that retrieves text data from my localhost. I have set up an HTTP server using Node.js which serves as a regular HTTP server. The serve ...

JavaScript not functioning properly with HTML loaded via .load()

I'm facing a perplexing dilemma: My issue revolves around this JS code: EDIT updated JS $(".img-thumb").on("click", function(){ // displaying the same behavior as .click() thumbID = $(this).attr("id"); console.log(thumbID); $(".gal-act" ...

What could be causing the readTextFile function to return undefined?

var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; function readFile(file) { let fileContents = new XMLHttpRequest(); fileContents.open("GET", file, false); fileContents.onreadystatechange = function () { ...

"Implementing a monorepo with turborepo for seamless deployment on Vercel: A step-by-step

There has been recent news about Turborepo being acquired by Vercel, sparking my interest to dive into it. To start, I initiated a turbo repo project with the following command: pnpx create-turbo Afterwards, I attempted to deploy it on Vercel by referring ...

"Encountering an 'Undefined function' error while implementing AJAX in the code

I'm encountering the issue Uncaught ReferenceError: GetLicenceUserList is not defined in the browser console when I utilize the function with $.ajax inside. However, the function works perfectly fine when I invoke it with just an alert("example& ...

The issue arises with getInitialProps as it fails to pass data to the page component while attempting to retrieve initial information and subsequently modify it using a button

I am currently working on a component located at app\page.tsx in Next.js v13.4.12, and it includes a button. My goal is to have the button trigger the handleClick function when clicked. The issue I'm facing is that the getInitialProps function ...

aligning JSON information with JavaScript object

I am currently in the process of setting up a sample dataset in JSON format for a JavaScript tutorial that I'm going through. Here's how the data object looks in JavaScript: app.Book = Backbone.Model.extend({ defaults: { coverImage: ...

Guide to adding information to a file in Nodejs depending on a condition

Looking for assistance on how to append an annotation (@Circuit(name = backendB)) to a file if the "createEvent" name exists and the annotation is not already present. I am unsure of the process, so any help on checking and appending using streams would ...

The code functions correctly on JSfiddle, however it is not executing properly on my website

When I tried to implement the code from this jsfiddle link: http://jsfiddle.net/mppcb/1/ on my website (), it didn't work as expected: Here is the HTML code snippet: <form id="myform" novalidate="novalidate"> <input type="text" name="fi ...

Unable to access the newly created object's properties following the instantiation of a new resource in AngularJS

Currently, I am in the process of developing a new Resource utilizing AngularJS that falls under the category of Person. After successfully creating this resource, my goal is to retrieve the id associated with the new resource from the server. it('sh ...

XMLHttpRequest Refusing to Send Data

This snippet of code is crucial for the custom extension: let url = "https://mywebsite.com/data.php"; function sendRequest() { var client = new XMLHttpRequest(); client.open("POST", url, true); client.setRequestHeader("Content-Type", "text/pla ...

Troubleshooting the "Failed to mount component" error in Vue: fixing template or render function definition issues

Struggling with writing a Vue component, encountering the issue: Failed to mount component: template or render function not defined. Tried various fixes like adding default when importing the component, but none of them seem to work. My component code is i ...

Having trouble invoking an established route within a different route in an Express JS project

While working with an Express JS application connected to a mySQL database, I encountered an issue when trying to fetch data from a pre-defined route/query: // customers.model.js CUSTOMERS.getAll = (result) => { let query = "SELECT * FROM custo ...

The POST variable consistently remains void

The approach I am using to handle the data sent with jquery.ajax involves sending an empty string by default. Whenever there is a change, I monitor the input for changes and resend the data. Everything seems to work fine in the console, but in PHP, $this-& ...

Guide to setting up an automated process in PHP

When setting up a tournament interface on my page: Users utilize functions like fopen() and fwrite() to create tournaments. The created tournaments must only start after a specific time, for example, 1 hour. This delay allows other users to join the tour ...

Submenu animation that "bursts onto the scene"

I'm facing an issue with my menu that has sub-items inside it. To achieve the animation effect I desire, I need to extract the width, height, and first-child's height of the sub-menu. While my animation is working most times, there are instances ...

Utilizing a functional component to incorporate a "load more" button in ReactJS

Hey everyone, I've come across this ReactJS code that I need some help with: function DisplaySolutions({solutions}) { const topSolutions = solutions.slice(0, 4); const remainingSolutions = solutions.slice(4); const [isD ...

Determine the instance's name as a string in JavaScript

Currently, I am utilizing Three.js in combination with javascript. Upon running the following line of code: console.log(this.scene.children[1]) I receive the following output in the console within Chrome: https://i.stack.imgur.com/6LBPR.png Is there a w ...

Discover a foolproof method for effortlessly examining an flv or mp4 file embedded within a webpage simply by

I've encountered a challenge with JavaScript. I can successfully check a flash object in a webpage when hovering over it, but I'm unsure how to achieve the same for flv or mp4 objects when either hovering over or moving away from them. Currently ...

ES6 syntax specification allows for the use of a fat arrow function for declaring React components

When learning React, I have noticed two different ways of declaring components. The first is using the classic fat arrow syntax with a return statement. const Component = () => { return ( <div>Hello</div> ) } Recently, I came ...