Home > Mobile >  How can I reset the value of a ref and keep an associated watcher working?
How can I reset the value of a ref and keep an associated watcher working?

Time:03-05

UPDATE:

I have achieved the desired behavior in my app the the MCV by changing resetArray:

function resetArray() {
  // myArray.value = [] // old version
  myArray.value.length = 0 // new version
}

But I still don't understand why my MCV doesn't work.

ORIGINAL POST:

Background

In an app I am building, I store data in an a ref, created as const myArray = ref([]), which takes the form of an array of objects. This array is only changed in the following ways:

  1. myArray.value[index] = {key: value}
  2. myArray.value = [].

In particular, at no time is an object in myArray modified, it is either created or replaced.

I later added a watch which took action on every to myArray.value. I discovered that after resetting myArray to [], the watcher stopped getting called.

Things I have tried:

  1. I confirmed that my usage of ref follows the guidelines in this SO answer regarding ref vs reactive.
  2. Refactoring to use watchEffect instead of watch. Did not help.
  3. Refactoring to use reactive rather than ref. Did not help.

My Issue

In the MCV below, modifying myArray by calling addToArray works as intended: myArray.length is rendered and the first watch is triggered.

Calling resetArray triggers only the second watch, but the first watch IS NOT triggered when addToArray is called afterwards.

My Question

How can I both keep the ability to set myArray to [] and trigger actions every time myArray changes?

My MCV

View my MCV on Vue SFC Playground

The below code is the content of App.vue in a Vue project created with npm init vue@latest:

<script setup>
import {ref, watch} from "vue"

const myArray = ref([])

function addToArray() {
  myArray.value.push("1")
}

function resetArray() {
  myArray.value = []
}

watch(myArray.value, () => {
  console.log("CLICKED!")
})

watch(myArray, () => {
  console.log("RESET! clicked won't get called again!")
})

</script>

<template>
  {{myArray.length}}<br />
  <button @click="addToArray">CLICK ME</button><br />
  <button @click="resetArray">RESET</button>
</template>

CodePudding user response:

  1. When watching a ref, use the ref itself -- not its value property -- as the watch source (the 1st argument to watch()).

  2. To observe new array assignments or item additions/removals, pass the deep:true option (the 3rd argument to watch()):

watch(
  myArray 1️⃣,
  () => { /* handle change */ },
  { deep: true } 2️⃣
)

demo

  • Related