VueJs 使计算属性具有反应性

Posted

技术标签:

【中文标题】VueJs 使计算属性具有反应性【英文标题】:VueJs make computed property reactive 【发布时间】:2019-06-22 10:16:14 【问题描述】:

我有一个像这样的 VueJS 组件

const MyComponent = Vue.extend(
  props: ["myHandle"],
  computed: 
    name: 
      get: function()  return myHandle.getName() ,
      set: function(newName)  myHandle.setName(newName) ,
    
  
)

问题是设置计算属性name不会触发VueJs更新属性。这意味着旧名称是在重新渲染时显示的内容。

现在,我对 VueJS 还很陌生,我可以看出这可能是代码异味,但问题是 myHandle 属性实际上是一个句柄,用于访问用 rust 编写的 WebAssembly 模块中的数据。 rust 代码是我的大部分状态/模型/真相来源所在的地方。

目前我发现的两个不满意的解决方案是:

    使用方法而不是计算属性来检索名称。基本上将getName 方法添加到我的组件并将我的模板代码从<p> Your name is name </p> 更改为<p> Your name is getName() </p>。这将导致 VueJs 不缓存。将来我计划进行昂贵的计算,这意味着不必要的性能成本

    将状态从 rust 复制到我的组件。我不想这样做,因为我会得到多个事实来源。

那么有没有办法:

A:让 VueJS 了解 myHandle.setName 是一种变异方法,应该会导致 name 计算属性被更新。

B:手动触发更新。

C用其他方式解决?

【问题讨论】:

【参考方案1】:

有一个简单的技巧 - dummy_toogle - 只需将它放在您的组件数据中:toggle:false 在你的 getter/setter 中: 得到:函数()this.toggle; ... 设置:函数(名称)...; this.toggle=!this.toggle; 现在 vue 会认为计算属性依赖于切换并在切换发生更改时重新计算它 + 你可以做一个非常愚蠢的回调并将它作为更新触发器传递给应用程序的非 vue 部分

【讨论】:

【参考方案2】:

我不知道你的 setName() 实现如何,但如果是的话

setName(newName) this.name = newName;

您可能遇到了这里描述的问题: https://vuejs.org/v2/guide/reactivity.html#Change-Detection-Caveats

我想补充一点,将 myHandle 作为道具进行变异可能不是一个好主意,因此我建议如果您可以重构代码以使用 myHandle 作为数据属性,请这样做。

【讨论】:

【参考方案3】:

计算属性根据其依赖项(数据、道具和其他计算属性)进行缓存。如果我理解正确,您的计算属性将不会是反应性的,因为唯一的依赖项是 myHandle,我认为这永远不会改变。这样看,Vue 只能通过实际调用方法来检查 getName 是否返回了不同的值,所以没有什么要缓存的。

如果名称只能从您的 Vue 组件中更改,您可以将其设置为数据字段并添加观察者以更新 WebAssembly 值。否则,如果名称可以从非 Vue 源更改,并且您每次都必须从处理程序中调用 getName 方法,那么您将不得不提出自己的机制(可能使用 debounce 函数来限制调用次数)。

【讨论】:

【参考方案4】:

希望这个例子对你有帮助

  <!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">

</head>
<body>
    <div id="app">
    <my-component :myhandle="myhandle">
    </my-component>

    <h2>Vue app Object: myhandle.name</h2>
</div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script>
    <script>
   Vue.component('my-component', Vue.extend(
        props: ["myhandle"],
        data () 
            return 
                name:""
            
        ,

        watch:  
            myhandle:
                handler (val, oldVal) 
                 console.log('Prop changed');
                // do your stuff
                ,
                deep: true, // nested data
            
    ,

        methods: 
            chName()
                this.myhandle.name = "Henry";
            
        ,
        template:'<div><h1>myhandle.name </h1><br><button @click="chName()">Cahnge name</button></div>',

        ),

        );

        var app = new Vue(
            el:'#app',
            data ()
                return 
                    myhandle:
                        name:'Jack'
                    
                
            

        );
    </script>
</body>
</html>

【讨论】:

以上是关于VueJs 使计算属性具有反应性的主要内容,如果未能解决你的问题,请参考以下文章

Vuejs Es6 类反应性

如何使 Vue 3 对象属性具有反应性

VueJs 组件的 Prop 相关计算属性对对象数组 Prop 更改没有反应

TypeScript:如何使函数具有反应性

Vue 计算属性不会在更新其反应性依赖项时更新

如何在Vuejs中将反应性道具传递给孩子