petite-vue组件实例数据不更新问题求助
Petite-Vue组件数据不更新问题排查与解决
问题描述
我有一个包含两个实例的petite-vue组件,其中一个实例运行正常(仅需执行一次,数据无需更新),但另一个实例在数据变化时无法按预期响应。具体表现为:跟踪littleData的更新索引功能正常,但在动态组件中使用littleData.data时无法同步更新。已查阅petite-vue官方文档,推测是对响应式原理存在理解疏漏。
以下是最小复现代码(setTimeout用于模拟petite-vue外部代码对数据的修改):
<!DOCTYPE html> <html lang="en"> <title>Minimum Test 1</title> <meta charset="utf-8"> <h2>Minimum Viable Example</h2> <div v-scope> <p>Count: {{Object.keys(bigData).length}}</p> <p v-if="littleData.index">Current: {{ littleData.index }}</p> <!-- Simulating other stuff happening in the outer context--> <h3>Doesn't update data:</h3> <div v-scope="temp1"></div> </div> <h3>Data on Creation:</h3> <div v-scope="temp2"></div> <template id="my-list-template"> <ul> <li v-for="item, key in data" :data-key="key">{{ item }}</li> </ul> </template> <script type="module"> import { createApp, reactive } from 'https://unpkg.com/petite-vue?module' const bigData = { 1: ['Apple', 'Banana', 'Carrot'], 2: ['Dog', 'Elephant', 'Ferret'], 3: ['Hotel', 'Golf', 'India'] } const littleData = reactive({ index: null, get data() { console.log(`... Data fetched at index ${this.index}`) return this.index ? bigData[this.index] : null } }) function MyList(props) { return { $template: '#my-list-template', id: props.id || null, data: props.data } } createApp({ // share it with app scopes bigData, littleData, temp1: MyList({ data: littleData.data }), temp2: MyList({ data: Object.values(bigData).map(i => i[0]) }) }).mount() // Imitate outside function modifying values function rotateIndex() { this.next = this.next ? 1 + littleData.index : 1 if (this.next == 4) { //Too high this.next = null } console.log(`Rotate! ${this.next} count: ${this.count}`) littleData.index = this.next this.count = this.count ? 1 + this.count : 1 if (this.count < 10) { // So this example doesn't go forever setTimeout(rotateIndex, 2000) } } setTimeout(rotateIndex, 2000) </script> </html>
问题根源
创建temp1实例时,传递的data: littleData.data是一次性获取当前值,并没有建立响应式依赖。当littleData.index变化时,littleData.data的 getter 虽然会触发,但temp1的data属性不会自动更新,因为它没有追踪littleData的变化。
修复方案
方案一:传递响应式对象本身,在组件内部访问 getter
修改MyList的实现,让它接收整个littleData对象,在组件模板中直接使用littleData.data,这样就能建立响应式依赖:
修改后的关键代码:
function MyList(props) { return { $template: '#my-list-template', id: props.id || null, // 直接传递响应式对象 listSource: props.source } } createApp({ bigData, littleData, temp1: MyList({ source: littleData }), temp2: MyList({ data: Object.values(bigData).map(i => i[0]) }) }).mount()
同时修改模板:
<template id="my-list-template"> <ul> <li v-for="item, key in listSource.data" :data-key="key">{{ item }}</li> </ul> </template>
方案二:在组件内部使用响应式 getter
如果不想修改组件的props结构,可以让MyList的data属性成为一个响应式的 getter,依赖传入的响应式对象:
修改后的MyList:
function MyList(props) { return { $template: '#my-list-template', id: props.id || null, // 用 getter 动态获取最新值,建立响应式依赖 get data() { return props.data() } } } // 创建实例时传递一个函数,返回最新的 littleData.data createApp({ bigData, littleData, temp1: MyList({ data: () => littleData.data }), temp2: MyList({ data: Object.values(bigData).map(i => i[0]) }) }).mount()
验证效果
修改后,当littleData.index变化时,temp1组件会自动重新渲染,展示最新的littleData.data内容。
内容的提问来源于stack exchange,提问作者alttag
相关产品推荐
相关产品推荐

