Vue.js中如何传递修改后的数据?解决provide未感知数组更新问题
问题原因
你遇到的核心问题是:provide 初始传递的是旧数组的引用,当你通过 this.cards = this.cards.concat(gameCards) 替换数组引用时,provide 里的 cards 并没有同步更新到新数组,导致依赖 inject 获取数据的组件拿到的还是初始的4个元素。另外注意你的原代码存在语法错误——methods 被写在了 created 函数内部,这会导致 prepareCards 方法无法正常执行,修正语法是前提。
解决方法
方案一:用响应式包装对象(Vue2/3通用)
把 cards 放在一个响应式的对象里,provide 这个包装对象,这样修改对象的属性时,子组件能感知到变化:
export default { components: { GameBoard, }, data() { return { cardStore: { cards: [ {id: "penguin", name: "penguin"}, {id: "tiger", name: "tiger"}, {id: "monkey", name: "monkey"}, {id: "lion", name: "lion"}, ] } }; }, provide() { return { cardStore: this.cardStore }; }, created() { this.prepareCards(); }, methods: { prepareCards() { let gameCards = []; for (let i = 0; i < this.cardStore.cards.length; i++) { gameCards.push({ id: this.cardStore.cards[i].name + 2, name: this.cardStore.cards[i].name + 2, }); } this.cardStore.cards = this.cardStore.cards.concat(gameCards); console.log("gameCards: " + JSON.stringify(this.cardStore.cards)); } } }
子组件通过 inject 接收后,使用 cardStore.cards 循环:
<CardResource v-for="card in cardStore.cards" :key="card.id" :id="card.id" :name="card.name" ></CardResource>
方案二:Vue2 专用 - 使用 Vue.observable
如果不想改数据结构,用 Vue.observable 创建响应式的提供对象,同步更新引用:
import Vue from 'vue'; export default { components: { GameBoard, }, data() { return { cards: [ {id: "penguin", name: "penguin"}, {id: "tiger", name: "tiger"}, {id: "monkey", name: "monkey"}, {id: "lion", name: "lion"}, ] }; }, provide() { return Vue.observable({ cards: this.cards }); }, created() { this.prepareCards(); }, methods: { prepareCards() { let gameCards = []; for (let i = 0; i < this.cards.length; i++) { gameCards.push({ id: this.cards[i].name + 2, name: this.cards[i].name + 2, }); } this.cards = this.cards.concat(gameCards); this._provided.cards = this.cards; console.log("gameCards: " + JSON.stringify(this.cards)); } } }
方案三:Vue3 专用 - 使用 ref/reactive
Vue3 中直接用响应式API定义数据,provide 响应式对象即可:
import { ref, provide } from 'vue'; export default { components: { GameBoard, }, setup() { const cards = ref([ {id: "penguin", name: "penguin"}, {id: "tiger", name: "tiger"}, {id: "monkey", name: "monkey"}, {id: "lion", name: "lion"}, ]); provide('cards', cards); const prepareCards = () => { let gameCards = []; for (let i = 0; i < cards.value.length; i++) { gameCards.push({ id: cards.value[i].name + 2, name: cards.value[i].name + 2, }); } cards.value = cards.value.concat(gameCards); console.log("gameCards: " + JSON.stringify(cards.value)); }; prepareCards(); return { cards }; } }
子组件接收方式:
<script setup> import { inject } from 'vue'; const cards = inject('cards'); </script> <template> <CardResource v-for="card in cards" :key="card.id" :id="card.id" :name="card.name" ></CardResource> </template>
内容的提问来源于stack exchange,提问作者Gunnar Polte
相关产品推荐
相关产品推荐

