当前位置: 首页 > news >正文

【Vue3】详细探究 watch ref 数组不生效的问题

结果

不废话,直接上结果:

方法arr.pusharr.splicearr[i] = …arr = …arr.length = 0
模板✔️✔️✔️✔️✔️
watch(arr) ✖️✖️✖️✔️✖️
watch(arr.value)✔️✔️✔️✖️✔️
watch(arr, { deep: true })✔️✔️✔️✔️✔️
watch(arr.value.length)⚠️⚠️⚠️⚠️⚠️
watch(() => arr.value)✖️✖️✖️✔️✖️
watch(() => arr.value.length)✔️✔️✖️✔️*✔️*

从结果来看,watch(arr, { deep: true }) 最为保险,与模板行为一致。但是 deep watch 太大的对象可能会影响性能。

你可以根据上面的表格来确定到底用哪一种方法。

说明:

  1. ✔️ 表示这一列的操作能触发这一行的 watch,✖️ 同理。
  2. ⚠️ 表示报错。
  3. 列头上的操作省去了 .value。因为是在模板中执行的代码,不用加 .value

(* 见下方解释)

解释

  1. watch(arr):监听的是 ref 的值,也就是数组的引用。只有整个数组被替换时才会触发。
  2. watch(arr.value):ref 中的非原始值底层会自动改用 reactive,因此 watch arr.value 相当于 watch 底层的 reactive 对象。当数组被整个替换后,watch 的依旧是原来的数组,而不是新的数组,所以 arr = ... 不会被触发。
  3. watch(arr, { deep: true }):相当于 1 和 2 的组合。
  4. watch(arr.value.length)arr.value.length 是个数字,不是 ref 对象、reactive 对象或者 getter 函数,因此这段代码根本无法执行。
  5. watch(() => arr.value):和 1 是一样的。这点在 Vue3 文档中也有提及。
  6. watch(() => arr.value.length):4 的正确书写版。因为 watch 的是 arr 的长度,不管 arr 发生了什么,只要长度变了就会触发。测试中的 arr = ... 恰好新旧数组长度不一致,所以可以触发。

测试代码

<script setup>
import { ref, watch } from 'vue'

const counter = ref(0);

const arr = ref([]);
const _watch = ref([]);
const _watchValue = ref([]);
const _watchDeep = ref([]);
const _watchLength = ref('[Vue warn]: Invalid watch source:  0 A watch source can only be a getter/effect function, a ref, a reactive object, or an array of these types. ');
const _watchGetter = ref([]);
const _watchGetterLength = ref([]);   

watch(arr, () => _watch.value = [...arr.value]);
watch(arr.value, () => _watchValue.value = [...arr.value]);
watch(arr, () => _watchDeep.value = [...arr.value], { deep: true });
// watch(arr.value.length, () => _watchLength.value = [...arr.value]);
watch(() => arr.value, () => _watchGetter.value = [...arr.value]);
watch(() => arr.value.length, () => _watchGetterLength.value = [...arr.value]);
</script>

<template>
  <table>
    <tbody>
      <tr><td>模板</td><td>{{ arr }}</td></tr>
      <tr><td>watch(arr)</td><td>{{ _watch }}</td></tr>
      <tr><td>watch(arr.value)</td><td>{{ _watchValue }}</td></tr>
      <tr><td>watch(arr, { deep: true })</td><td>{{ _watchDeep }}</td></tr>
      <tr><td>arr.value.length</td><td>{{ _watchLength }}</td></tr>
      <tr><td>watch(() => arr.value)</td><td>{{ _watchGetter }}</td></tr>
      <tr><td>watch(() => arr.value.length)</td><td>{{ _watchGetterLength }}</td></tr>
    </tbody>
  </table>

  <div class="button-group">
    <button @click="arr.push(counter++)">arr.push(i)</button>
    <button @click="arr.splice(0, 1)">arr.splice(0, 1)</button>
    <button @click="arr[0] = counter++">arr[0] = i</button>
    <button @click="arr = [counter]">arr = [i]</button>
    <button @click="arr.length = 0">arr.length = 0</button>
  </div>
</template>

<style>
/* 样式由 Claude Sonnet 3.5 完成 */
* {
  font-family: consolas;
}
table {
  border-collapse: collapse;
  margin: 20px 0;
  width: 100%;
  max-width: 800px;
}

td {
  border: 1px solid #ddd;
  padding: 8px 12px;
}

td:first-child {
  font-weight: bold;
  background-color: #f5f5f5;
  width: 300px;
}

.button-group {
  margin: 20px 0;
}

button {
  margin-right: 10px;
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

button:hover {
  background-color: #45a049;
}

button:last-child {
  margin-right: 0;
}
</style>

相关文章:

  • LeetCode 2380 二进制字符串重新安排顺序需要的时间
  • 无人机楼宇间物资运输技术详解
  • 【算法 C/C++】二维前缀和
  • 【密码学——基础理论与应用】李子臣编著 第三章 分组密码 课后习题
  • mysql的MGR
  • 在mac中设置环境变量
  • 校验pytorch是否支持显卡GPU 不支持卸载并安装支持版本
  • 报表控件stimulsoft操作:使用 Angular 应用程序的报告查看器组件
  • ngx_openssl_create_conf
  • Zookeeper实践指南
  • BI 工具响应慢?可能是 OLAP 层拖了后腿
  • 【报错】微信小程序预览报错”60001“
  • unity使用mesh 画图(1)
  • Spring 事务和事务传播机制
  • 接口测试笔记
  • C语言(23)
  • Flutter 学习之旅 之 flutter 使用flutter_native_splash 简单实现设备启动短暂白屏黑屏(闪屏)的问题
  • matlab慕课学习3.1
  • Flutter中网络图片加载显示Image.network的具体用法
  • QwQ-32B通用能力测评的详细分析
  • 外交部发言人就第78届世界卫生大会拒绝涉台提案发表谈话
  • 网络直播间销售玩具盲盒被指侵权,法院以侵犯著作权罪追责
  • 周国辉谈花开岭现象 :年轻的公益人正在用行动点亮希望
  • 关税影响下沃尔玛想涨价,特朗普施压:自行承担,别转嫁给顾客
  • 法律顾问被控配合他人诈骗酒店资产一审判8年,二审辩称无罪
  • 官方通报汕头违建豪宅“英之园”将强拆:对有关人员严肃追责问责