简体   繁体   English

VueJS 3:更新值并避免监视

[英]VueJS 3: update value and avoid watch

I am coding a table with pagination component, and I use multiple v-model and watch on these variables to fetch the data.我正在编写一个带有分页组件的表格,我使用多个 v-model 并watch这些变量来获取数据。 When perPage is updated, I want to reset page to 1. So I did it in my watch method but of course, watch is triggered twice (for perPage and then page ).perPage更新时,我想将page重置为 1。所以我在watch方法中这样做了,但是当然, watch被触发了两次(对于perPage ,然后是page )。

Is it possible to update the variable and disable watch at this moment?此时是否可以更新变量并禁用手表?

Here is my current code:这是我当前的代码:


<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 return when I reset page :我发现的唯一解决方法是在我重置page时返回:

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

  fetchItems()

  ...
})

It is working in my case but for some another cases I would like to update without trigger the watch method.它适用于我的情况,但对于其他一些情况,我想在不触发 watch 方法的情况下进行更新。

Thanks!谢谢!

Create another watcher for perPage :perPage创建另一个观察者:

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
})

It's recommended to create watch for a single property separately to avoid unnecessarily updates and conflicts.建议单独为单个属性创建监视以避免不必要的更新和冲突。 For the first watch try to replace it with watchEffect like since you're not using the old/new value:对于第一个手表,尝试用watchEffect替换它,因为您没有使用旧/新值:

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

Considering that the state is changed through v-model , it needs to be observed with a watcher.考虑到 state 是通过v-model改变的,需要用 watcher 来观察。

In order to avoid a watcher to be triggered multiple times, it should implement additional conditions like shown in the question, but it also needs to not skip an update when page is already 1 , this won't result in additional update:为了避免观察者被多次触发,它应该实现问题中显示的附加条件,但是当page已经是1时它也需要不跳过更新,这不会导致额外的更新:

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

    if (newPage !== 1)
      return
  }

Otherwise there need to be multiple watchers, like another answer suggests.否则,就像另一个答案所暗示的那样,需要有多个观察者。 In case a watcher that causes asynchronous side effects ( fetchItems ) shouldn't be triggered more than it needs, and there are other causes for this to happen besides perPage , it can be debounced, eg:如果导致异步副作用 ( fetchItems ) 的观察者不应被触发超过其需要的次数,并且除了perPage之外还有其他原因导致这种情况发生,则可以对其进行去抖动,例如:

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

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

Thank you for all your answers, I finally found what I was looking for using VueUse - watchIgnorable :感谢您的所有回答,我终于找到了使用VueUse - watchIgnorable的内容:

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

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

  fetchItems()
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM