Subscribe on changes!

v-for with ref not working as suggested in documentation in some scenarios

avatar
Mar 15th 2021

Version

3.0.7

Steps to reproduce

Original Docs:

import { onBeforeUpdate, onUpdated } from 'vue'

export default {
  setup() {
    let itemRefs = []
    const setItemRef = el => {
      if (el) {
        itemRefs.push(el)
      }
    }
    onBeforeUpdate(() => {
      itemRefs = []
    })
    onUpdated(() => {
      console.log(itemRefs)
    })
    return {
      setItemRef
    }
  }
}

What is expected?

Filled array for component lifetime

What is actually happening?

After component update array is empty, but lifetime is continue.


Temporary solution: Tip: Only use and export. Authors: @NataliaTepluhina

function useListRef<T>() {
  const elements = ref<T[]>([])
  const active = ref<boolean>(false)

  watch(active, (isActive) => {
    if (isActive) {
      nextTick(() => active.value = false)
    }
  })

  function addRef(el) {
    if (!active.value) {
      elements.value = []
      active.value = true
    }
    el && elements.value.push(el)
  }

  return {
    elements,
    addRef,
  }
}
avatar
Mar 15th 2021

Please provide a boiled down issue like asked in the new issue helper. It contains a js fiddle you should use. Closing until one is provided

avatar
Mar 15th 2021

@posva I reopened as I'm familiar with the issue myself. Already started talking to some of our team how to best resolve this.

It's not strictly a bug as it's more of a conceptual blind spot we have to fill somehow. the recommended approach from the docs can fail under certain circumstances, i.e. this:

<template>
  <child-component>
    <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
      {{ item }}
    </div>
  </child-component>
</template>

<script>
  import { ref, reactive, onMounted, onBeforeUpdate } from 'vue'

  export default {
    setup() {
      const list = reactive([1, 2, 3])
      const divs = ref([])

      onMounted(() => list.push(4))

      // this will not run when `list` is mutated, 
      // because `list` is a slot dependency, tracked by the `child`, not this parent.
      onBeforeUpdate(() => {
        divs.value = []
      })

      return {
        list,
        divs
      }
    }
  }
</script>
avatar
Mar 15th 2021

@posva I was trying to use codepen, codesandbox, I dont understand these instruments, sorry, but it is really don't working from docs, who is writing doc page with "v-for + article"?

avatar
Mar 15th 2021

https://github.com/vuejs/docs-next/blame/master/src/guide/migration/array-refs.md For avoid these confuses we need test docs examples, it is possible?))

avatar
Mar 15th 2021

Because In my opinion, The system is to blame, not the people and the system needs to be improved

avatar
Apr 1st 2021

Yes, I also have such a problem. This watch for :ref only works on the penultimate push.

https://codesandbox.io/s/vue3-refs-q6g6p?file=/src/App.vue

avatar
Apr 3rd 2021

@bazuka5801 Just to be clear: the docs example isn't generally failing. it's failing under specific conditions that you guys must have encountered (can't say more as you couldn't provide a reproduction). Hence a test wouldn't really have helped.

In can't talk to your specific situation as you never provided a complete example in the issue. I provided an example of specific circumstance under which it's failing and a short explanation as to why.

As i write, it's a conceptual issue we have to address and it's not as straightforward as it may seem.

avatar
Apr 3rd 2021

@LinusBorg in most projects, public components this "specific conditions" used. It should be fixed.

avatar
Apr 3rd 2021

It should be fixed.

Did any of us say anything to the contrary?

avatar
Apr 5th 2021

It should be fixed.

Did any of us say anything to the contrary?

No.