乐趣区

关于前端:Vue3第11课重温computed与watch

## computed
> 筹备写一个对于汽车销量的无序数组,并返回展现销量排名前 3 的。

<template>
销量总览:
<ul>

<li 
    v-for="(car, idx) in carList" 
    :key='idx'
 >
  {{car.name + ':'+ car.count}}
</li>

</ul>
前三销量:
<ul>

<li 
    v-for="(car, idx) in topThreeList" 
    :key='idx'
 >
  {{car.name + ':'+ car.count}}
</li>

</ul>
</template>

<script lang=”ts”>
import {defineComponent, reactive, computed, toRefs} from “vue”;
export default defineComponent({
setup() {
const data = reactive({

 carList: [
   {
     name: 'golf',
     count: 200
   },
   {
     name: 'mg6',
     count: 680
   },
   {
     name: 'foucs',
     count: 903
   },
   {
     name: '影豹',
     count: 1000
   },
   {
     name: 'uni-v',
     count: 666
   }
 ]

})
const topThreeList = computed(() => {

 let list = JSON.parse(JSON.stringify(data.carList)).sort((a, b) => {return b.count - a.count})
 return list.slice(0, 3)

})

return {...toRefs(data),
  topThreeList
};

},
});
</script>

> 接下来看一下成果

![alt](https://uploadfiles.nowcoder.com/images/20221201/376118598_1669880499177/D2B5CA33BD970F64A6301FA75AE2EB22)

> 对于 `computed` 的一些非凡之处, 官网文档是这样说的,例如

#### 1. computed 与办法的区别

<script setup>
import {reactive, computed} from ‘vue’

const author = reactive({
name: ‘John Doe’,
books: [

'Vue 2 - Advanced Guide',
'Vue 3 - Basic Guide',
'Vue 4 - The Mystery'

]
})

// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? ‘Yes’ : ‘No’
})
</script>

<template>
<p>Has published books:</p>
<span>{{publishedBooksMessage}}</span>
</template>

> 成果如下

![alt](https://uploadfiles.nowcoder.com/images/20221201/376118598_1669880862864/D2B5CA33BD970F64A6301FA75AE2EB22)

> 在表达式中像这样调用一个函数也会取得和计算属性雷同的后果:

// 模板中
<p>{{calculateBooksMessage() }}</p>

// 组件中
function calculateBooksMessage() {
return author.books.length > 0 ? ‘Yes’ : ‘No’
}

> 若咱们将同样的函数定义为一个办法而不是计算属性,两种形式在后果上的确是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。一个计算属性仅会在其响应式依赖更新时才从新计算。这意味着只有 author.books 不扭转,无论多少次访问 publishedBooksMessage 都会立刻返回先前的计算结果,而不必反复执行 getter 函数。> 这也解释了为什么上面的计算属性永远不会更新,因为 Date.now() 并不是一个响应式依赖:

const now = computed(() => Date.now())


> 相比之下,办法调用总是会在重渲染产生时再次执行函数。那么,须要缓存机制的起因,** 当然就是性能 **

#### 2. 不要在计算属性中做异步申请或者更改 dom,另外防止间接批改计算属性值

--- 

## watch 侦听器

在 Vue3 中,watch 有了更弱小的性能

#### 1. 根本用法

<template>
<input type=’text’ v-model=’name’ />
<p>{{msg}}</p>
</template>

<script lang=”ts”>
import {defineComponent, reactive, ref, watch} from “vue”;
export default defineComponent({
setup() {

const msg = ref('hello');
const name = ref('');
watch(name, (v) => {msg.value = 'hello' + v})
return {
  msg,
  name
}

},
});
</script>

![alt](https://uploadfiles.nowcoder.com/images/20221201/376118598_1669883027690/D2B5CA33BD970F64A6301FA75AE2EB22)

#### 2. 侦听数据源类型

`watch` 的第一个参数能够是不同模式的“数据源”:它能够是一个 ref (包含计算属性)、一个响应式对象、一个 getter 函数、或多个数据源组成的数组:

const x = ref(0)
const y = ref(0)

// 单个 ref
watch(x, (newX) => {
console.log(x is ${newX})
})

// getter 函数
watch(
() => x.value + y.value,
(sum) => {

console.log(`sum of x + y is: ${sum}`)

}
)

// 多个起源组成的数组
watch([x, () => y.value], ([newX, newY]) => {
console.log(x is ${newX} and y is ${newY})
})

** 留神,你不能间接侦听响应式对象的属性值,例如:**

const obj = reactive({count: 0})

// 谬误,因为 watch() 失去的参数是一个 number
watch(obj.count, (count) => {
console.log(count is: ${count})
})

** 这里须要用一个返回该属性的 getter 函数:**

// 提供一个 getter 函数
watch(
() => obj.count,
(count) => {

console.log(`count is: ${count}`)

}
)

#### 3. 深层侦听器 (审慎应用)

你也能够给下面这个例子显式地加上 deep 选项,强制转成深层侦听器:

watch(
() => state.someObject,
(newValue, oldValue) => {

// 留神:`newValue` 此处和 `oldValue` 是相等的
// * 除非 * state.someObject 被整个替换了 

},
{deep: true}
)


#### 4. watchEffect()

watch() 是懒执行的:仅当数据源变动时,才会执行回调。但在某些场景中,咱们心愿在创立侦听器时,立刻执行一遍回调。

watchEffect(async () => {
const response = await fetch(url.value)
data.value = await response.json()
})

 大家能够参考 [这个例子](https://cn.vuejs.org/examples/#fetching-data),它用了 watchEffect,还展现了如何做响应式的数据申请。#### 5. 进行侦听器
要手动进行一个侦听器,请调用 watch 或 watchEffect 返回的函数:

const unwatch = watchEffect(() => {})

// … 当该侦听器不再须要时
unwatch()

退出移动版