【问题标题】:Vue 3 ref is not updating into component on templateVue 3 ref 未更新为模板上的组件
【发布时间】:2021-06-20 08:11:24
【问题描述】:

我正在使用vue3-carousel 包在我的项目中显示images/videos。对于我来说,我遇到了意想不到的问题。我不知道为什么ref 没有在我的模板上更新。我在vue 组件中有这个逻辑,如下所示。

模板:

<carousel v-if="presentedImages.length" :items-to-show="2" :snapAlign="'start'" :breakpoints="breakpoints" :wrap-around="true">
    <slide class="slide" v-for="image in presentedImages" :key="image.id">
        <img v-if="image.attachment_url" class="videoFile" :src="image.attachment_url" />
        <div  @click="deleteImage(image.id)" class="fa-stack remove-button cross-btn">
            <i class="fa fa-times"></i>
        </div>
    </slide>
    <template #addons>
        <navigation />
    </template>
</carousel>

脚本:

const presentedImages = ref(props.images);
const deleteImage = (id) => {
    removeAttachment(id).then(res => {
        presentedImages.value = presentedImages.value.filter(img => {
            return img.id !== id;
        });
    })
    .catch(err => console.log(err))
}

你能回答我为什么删除图像时轮播组件中的数据没有更新吗?仅供参考:Ref 正在脚本中更新。

【问题讨论】:

    标签: javascript vuejs3 vue-composition-api vue3-carousel


    【解决方案1】:

    看看下面我的例子...

    这不是你使用道具的方式。通过执行const presentedImages = ref(props.images);,您正在创建新的ref,当前值为prop.images。这意味着父组件和子组件正在使用相同的数组实例......首先

    因此,如果您在我的示例中仅使用 + 按钮,一切都很好...

    但是一旦父母(使用reset按钮)或孩子(-按钮)用不同的数组替换他们自己的ref的值,整个例子就坏了......

    在 child 中创建 ref 以捕获 prop 的响应值的正确方法如下:

    import { toRefs } from 'vue'
    
    const { images: presentedImages } = toRefs(props);
    

    只要父级更改推送到道具的数据以任何方式,此引用就会更改。但是这个参考也是只读的。因为道具一直是one way only

    这个问题有两种解决方案:

    1. 永远不要用新数组替换 prop/child ref 的值,只修改数组(使用splice 而不是filter)。这是可能的,但被认为是“肮脏的”。因为通过更新 ref 很容易破坏组件。就像一个地雷等待一个粗心的程序员......

    2. 使用上面的“正确”方式并接受 Vue 的原则——props 是只读的。只有拥有数据的组件才能修改它。所以你的组件应该只触发一个事件,父组件应该从数组中删除图像......

    const generateItems = () => [{
        id: 1,
        name: 'item 1'
      },
      {
        id: 2,
        name: 'item 2'
      },
      {
        id: 3,
        name: 'item 3'
      },
    ]
    const app = Vue.createApp({
      setup() {
        const items = Vue.ref(generateItems())
    
        let index = 100
        const addItem = () => {
          items.value.push({
            id: index,
            name: `item ${index}`
          })
          index++
        }
        const reset = () => {
          items.value = generateItems()
        }
    
        return {
          items,
          addItem,
          reset
        }
      },
      template: `
        Parent ({{ items.length}} items): {{ items }}
        <br>
        <button @click="addItem">+</button>
        <button @click="reset">reset</button>
        <hr>
        <child :items="items" />
      `,
    })
    
    app.component('child', {
      props: ["items"],
      setup(props) {
        const myItems = Vue.ref(props.items)
    
        /*
          This is better byt the ref is read only!
        */
        // const { items: myItems } = Vue.toRefs(props)
    
        let index = 4
        const addItem = () => {
          myItems.value.push({
            id: index,
            name: `item ${index}`
          })
          index++
        }
    
        const removeItem = (id) => {
          myItems.value = myItems.value.filter(img => {
            return img.id !== id;
          });
        }
    
        return {
          myItems,
          addItem,
          removeItem
        }
      },
      template: `
      <div> Child </div>
      <button @click="addItem">+</button>
      <hr>
      <div v-for="item in myItems" :key="item.id"> {{ item.name }} <button @click="removeItem(item.id)">-</button> </div>
      `,
    })
    
    app.mount('#app')
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.0.7/vue.global.js" integrity="sha512-+i5dAv2T8IUOP7oRl2iqlAErpjtBOkNtREnW/Te+4VgQ52h4tAY5biFFQJmF03jVDWU4R7l47BwV8H6qQ+/MfA==" crossorigin="anonymous"></script>
    
    <div id="app">
    </div>

    【讨论】:

    • 感谢您分享您的想法!我尝试过不同的方法。但似乎图书馆兑现了轮播项目的价值。我可以更新我的组件中的项目,但它不会在轮播组件中更新。
    • 我现在正在使用这个结构const { images: presentedImages } = toRefs(props);。但是,当我更改了presentImages 的值时,我在开发人员工具中出现了这个错误。 ** 对关键“图像”的设置操作失败:目标是只读的。** 我知道 props 和 refs 是不可变的。但我为presentedImages 设置了值...presentedImages.value = presentedImages.value.filter(img =&gt; { return img.id !== id; });
    • 这是意料之中的。再次阅读我的答案。您不能更改父组件的 prop 值。使用事件并移除父级中的图像...
    • 这是图书馆的问题。我尝试了不同的方法。添加/删除 div 时有效,如果使用库组件操作会出现问题
    猜你喜欢
    • 2021-11-21
    • 1970-01-01
    • 2019-07-29
    • 2020-10-08
    • 2021-06-05
    • 2021-08-21
    • 1970-01-01
    • 2021-12-31
    • 2020-11-12
    相关资源
    最近更新 更多