Vue 中 computed 修改使用的属性
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Vue 中 computed 修改使用的属性相关的知识,希望对你有一定的参考价值。
参考技术A学习 Vue 计算属性的时候有个疑问❓, 那就是在计算属性中修改使用的属性值, 会不会因为 Vue 的响应式而造成死循环
计算属性可以理解为是一个 getter 函数, 获取新值, 但是 vue 会做一层缓存, 只有改变才会重新计算
举个栗子🌰 :
假设有个属性叫 name , 现在需要一个计算属性 newName , 但是需要在取 newName 的时候再把 name 改成初始值, 由于 name 每次修改的值都不是上一次的值都会触发响应式, 理论上写一个点击方法用来修改一次 name 的值, 处理流程应该是 name --> newName --> name --> newName --> name --> newName .... 然而事实并不会如此
首先要知道流程是什么?
修改 name 的值, 会触发响应式, 那么响应式会调用 trigger 函数, trigger 函数最终会调用 newName 里的响应式副作用( ReactiveEffect )的 scheduler , 而 scheduler 可以根据 ComputedRefImpl 查到实现为 triggerRefValue(this); 也就是调用计算属性 get value 函数, 此时就是在执行 ReactiveEffect 捕捉的 getter 函数并且将该副作用设置为活跃状态的 ReactiveEffect , 也是外面写的 newName 函数, 在这里执行 newName 就会出现对 name 赋新值触发新的 trigger
可以注意的是 trigger 的 key 为正在修改的属性名称, 也就是 name , vue 使用一个 map 通过 key 为 name 来存储 ReactiveEffect 对象
回到上面, 在 newName 中触发新的 trigger , 实际上最后执行的是 triggerEffects , 在这里会对所有的副作用进行遍历, 当然在 newName 中副作用只有一个也就是通过 name 为 key 存储的 ReactiveEffect 对象, 此时它也是活跃状态的 ReactiveEffect , 根据 triggerEffects 中 effect !== activeEffect || effect.allowRecurse 这个判断, 正在执行的 effect 不等于活跃状态的 effect 或者允许递归才会调度 scheduler , 由于当前的 effect === activeEffect, 所以不会执行 newName 的 scheduler 也就不会去执行
结果: vue 内部处理的可能出现死循环的情况, 估计以前某个版本会出现死循环, 到现在 eslint 都会提示 Unexpected side effect in "newName" computed property. 错误
Vue2 computed中的setter
文章目录
前言
Vue2 computed
中setter
的使用方法, 在什么情况下使用setter
, 对于setter
的一些个人见解.
一、可写计算属性setter
计算属性默认仅能通过计算函数得出结果。当你尝试修改一个计算属性时,你会收到一个运行时警告。
computed
计算属性内直接写的话是默认编辑getter
, 但是getter
部分严格遵守computed
最佳实践风格(见第二章), 在这种限制下可能会使需求的完成受阻.
我的理解是, setter
的存在并非为了在最佳实践规则上开个口子退而求其次的妥协以完成目标, 而是通过对setter
的使用可以实现在最佳实践风格的基础上达到目的, 比如在计算属性被赋值的解决方案中使用setter
, 可以在操作data
数据的情况(即违反不产生副作用规则的情况)下避免标红.
呃, 计算属性被 “赋值” 这个说法对我造成过一些误导, 就个人而言, 我感觉这更像是在 “传参”, 虽然这看起来的确是赋值操作.
看起来是这样的:
// 在某个函数里
this.计算属性 = '参数'
但是computed
对此的应对:
computed:
计算属性:
get() ,
// setter
set(newValue) // newValue为赋的值
// 函数体
是作为参数传入setter
函数中执行, 而不是直接把这个计算属性变成变量那样的随意重赋值的东西.
二、为何使用setter
Vue中有些computed
属性使用的不推荐方案, 但是有时为了完成需求又需要这些不推荐的方案.
setter
可以解决这些情况, 让computed
在那几种特殊情况下依旧能以最佳实践方案运作.
1.需要修改计算属性值
Vue并不推荐 并且 不建议直接修改计算属性值:
从计算属性返回的值是派生状态。可以把它看作是一个“临时快照”,每当源状态发生变化时,就会创建一个新的快照。更改快照是没有意义的,因此计算属性的返回值应该被视为只读的,并且永远不应该被更改——应该更新它所依赖的源状态以触发新的计算。
我的理解是, 我们应该通过主动改变那些源状态(就是影响本次computed
计算结果的源)以驱动computed
去计算需要的值, 而不是在不断变动并不稳定的computed
返回值上直接做更改.
这点的体现是如果去除computed
中的setter
后依旧直接为计算属性赋值, 那么将会触碰这条红线引发报错:
Computed property "xxx" was assigned to but it has no setter.
2.不可避的计算属性副作用
我逐渐习惯Eslint
了.
Eslist
下的computed
(我是说它的getter
内)禁止进行对data
数据的赋值操作, 会标红计算属性不应有副作用, 这里的副作用也包括DOM更改和网络请求等等.
计算属性的计算函数应只做计算而没有任何其他的副作用,这一点非常重要,请务必牢记。举例来说,不要在计算函数中做异步请求或者更改 DOM!一个计算属性的声明中描述的是如何根据其他值派生一个值。因此计算函数的职责应该仅为计算和返回该值。在之后的指引中我们会讨论如何使用监听器根据其他响应式状态的变更来创建副作用。
如果在setter
中进行则不会有这种报错情况, 不过我还是不会在computed
里给data
赋值的.
三、使用setter
<template>
<div id="demo">
<button @click="changeComputed">changeComputed</button>
<input type="text" v-model="firstName" />
<input type="text" v-model="lastName" />
</div>
</template>
<script>
export default
data()
return
firstName: "John",
lastName: "Doe",
;
,
computed:
fullName:
get()
return this.firstName + " " + this.lastName;
,
set(newValue)
this.firstName = newValue;
this.lastName = newValue.split(" ");
,
methods:
changeComputed()
this.fullName = 'bai X'
;
</script>
在这个过程中通过setter
修改源状态驱动computed
的getter
再次触发生成了新的值, 遵循了避免直接修改计算属性值的建议.
但是如果setter
并没有对计算属性getter
中的源状态造成影响, getter
将不会重新执行, 即 并非触发setter
就一定会触发getter
, 他们两个是相互独立的, 对应计算属性的两种用法, 如果你对计算属性进行写入操作, 那就先过setter
, 如果本次setter
对源状态有影响, 那么也过一次getter
, 如果只是调用计算属性, 那么只过getter
.
至于"计算函数不应有副作用", 我们的确在computed
中对data
数据进行了修改, 这似乎并未能避免…
总结
以上是关于Vue 中 computed 修改使用的属性的主要内容,如果未能解决你的问题,请参考以下文章