Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

331
Visualizações
Vue js - ref within v-for loop always returning null

I am trying to access an element in Vue as I want to see when it's class changes (I'm using Bootstrap so I want to watch for when a class changes to shown). The problem is that as soon as I put a ref'd element into a v-for loop it always returns null. I have tried appending the ref's name with the index of the loop item, and then trying to log this to the console it just always returns 'null'.

As soon as I take the element out of the v-for loop it returns the element fine.

I can't seem to find a solution. Is this something that Vue just simply doesn't support? If not, is there a better way for me to watch the DOM to see if an element's class changes?

P.S. I'm using the composition API.

Template:

<template>
    <div v-for="room in rooms" :key="room.id" class="">
        <p class="test" :ref="'test'+room.id">Hello world</p>
    </div>
</template

Script:

setup(){
      const test1 = ref(null)

      onMounted(() => {
          console.log("test1: ", test1.value)
      })

      return { test1 }
}
about 4 years ago · Juan Pablo Isaza
2 Respostas
Responde à pergunta

0

Template refs in a v-for

There's a known bug (vuejs/core#5525), where array refs are not properly populated.

One workaround is to bind a function that pushes the element refs into the array:

                       👇
<p class="test" :ref="el => roomRefs.push(el)">Hello world</p>

demo 1

Watching class changes

To observe changes to the class attribute of the elements, use a MutationObserver.

mounted hook: For each roomRefs item:

  1. Create a MutationObserver with a callback that handles mutations (i.e., a change to the observed attribute).

  2. Use that MutationObserver instance to observe the class attribute on the roomRefs item.

  3. Collect each observer into an array, as we'll need to disconnect the observer upon unmounting.

unmounted hook:

  1. disconnect all observers to stop watching for changes. This cleanup step is necessary to avoid a memory leak.
export default {
  props: {
    rooms: {
      type: Array,
      required: true,
    },
  },
  setup() {
    const roomRefs = ref([])
    let observers = []

    onMounted(() => {
      1️⃣
      observers = roomRefs.value.map(roomEl => {
        const observer = new MutationObserver(mutations => {
          for (const m of mutations) {
            const newValue = m.target.getAttribute(m.attributeName)
            console.log('class changed', { roomEl, newValue, oldValue: m.oldValue })
          }
        })
        2️⃣
        observer.observe(roomEl, {
          attributes: true,
          attributeOldValue: true,
          attributeFilter: ['class'],
        })
        3️⃣
        return observer
      })
    })
    4️⃣
    onUnmounted(() => observers.forEach(obs => obs.disconnect()))
  }
}

demo 2

about 4 years ago · Juan Pablo Isaza Relatório

0

This looks like a pretty common problem, so I went digging through the Vue source and found the following:

It's a limitation of the way Vue does updates and renders. If you have multiple s for the same template, then each of them has its own patch queue. Each patch queue gets processed on its own schedule, so it's possible for one to finish before another even starts. If that happens, then one of the queued updates won't happen. That would mean Vue wouldn't detect changes to your element and hence wouldn't do any re-rendering at all, which is why your element doesn't show up in your console output!

You can work around this by making sure all update queues finish before each other begins, which we can do by adding an update: { sync: true } config to your component in question. This will force Vue to process all of your update queues synchronously before processing any other changes in the application.

You could also add a sync: true config to your parent's component that wraps all of your other components and make sure they all sync.

<script>
  setup() {
    const test1 = ref(null)

    onMounted(() => {
      console.log("test1: ", test1.value)
    })

    return { test1 }
  }

  render() {
      return (
        <div>Hello World</div>
      )}

  </script>

about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda