You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 15:08:38