首页 > 其他分享 >第四十二篇 vue - 进阶主题 - 深入响应式系统

第四十二篇 vue - 进阶主题 - 深入响应式系统

时间:2023-04-05 17:47:42浏览次数:40  
标签:vue const 进阶 onTrack value 响应 Vue 四十二篇 debugger

响应式系统

Vue 最标志性的功能就是其低侵入性的响应式系统。组件状态都是由响应式的 JavaScript 对象组成的。当更改它们时,视图会随即自动更新。这让状态管理更加简单直观,但理解它是如何工作的也是很重要的,这可以帮助我们避免一些常见的陷阱。在本节中,我们将深入研究 Vue 响应性系统的一些底层细节

什么是响应性

这个术语在今天的各种编程讨论中经常出现,但人们说它的时候究竟是想表达什么意思呢?本质上,响应性是一种可以使我们声明式地处理变化的编程范式

Vue 中的响应性是如何工作的

局部变量的读写,原生 JavaScript 没有提供任何机制能做到这一点。但是,我们是可以追踪对象属性的读写的

在 JavaScript 中有两种劫持 property 访问的方式:getter / setters 和 Proxies

Vue 2 使用 getter / setters 完全是出于支持旧版本浏览器的限制。而在 Vue 3 中则使用了 Proxy 来创建响应式对象,仅将 getter / setter 用于 ref

unction reactive(obj) {
  return new Proxy(obj, {
    get(target, key) {
      track(target, key)
      return target[key]
    },
    set(target, key, value) {
      target[key] = value
      trigger(target, key)
    }
  })
}

function ref(value) {
  const refObject = {
    get value() {
      track(refObject, 'value')
      return value
    },
    set value(newValue) {
      value = newValue
      trigger(refObject, 'value')
    }
  }
  return refObject
}

运行时 vs 编译时 响应性

Vue 的响应式系统基本是基于运行时的。追踪和触发都是在浏览器中运行时进行的。运行时响应性的优点是,它可以在没有构建步骤的情况下工作,而且边界情况较少。另一方面,这使得它受到了 JavaScript 语法的制约。

我们在前面的示例中已经提到了一个问题:JavaScript 并没有提供一种方式来拦截对局部变量的读写,因此我们始终只能够以对象属性的形式访问响应式状态,也就因此有了响应式对象和 ref
我们正在通过响应性语法糖这一实验性功能去尝试减少冗余代码

let A0 = $ref(0)
let A1 = $ref(1)

// 在变量读取时追踪
const A2 = $computed(() => A0 + A1)

// 在变量写入时触发
A0 = 2

这个代码段会被编译成没有该转换时的样子,即自动地为所有变量引用处添加上 .value。响应性语法糖让 Vue 的响应式系统变成了一个运行时 + 编译时结合的复合系统

响应性调试

Vue 的响应性系统可以自动跟踪依赖关系,但在某些情况下,我们可能希望确切地知道正在跟踪什么,或者是什么导致了组件重新渲染

1、组件调试钩子
我们可以在一个组件渲染时使用 renderTracked 生命周期钩子来调试查看哪些依赖正在被使用,或是用 renderTriggered 来确定哪个依赖正在触发更新。这些钩子都会收到一个调试事件,其中包含了触发相关事件的依赖的信息。推荐在回调中放置一个 debugger 语句,使你可以在开发者工具中交互式地查看依赖

export default {
  renderTracked(event) {
    debugger
  },
  renderTriggered(event) {
    debugger
  }
}

组件调试钩子仅会在开发模式下工作
2、计算属性调试
我们可以向 computed() 传入第二个参数,是一个包含了 onTrack 和 onTrigger 两个回调函数的对象:

  1、onTrack 将在响应属性或引用作为依赖项被跟踪时被调用
  
  2、onTrigger 将在侦听器回调被依赖项的变更触发时被调用
  
这两个回调都会作为组件调试的钩子,接受相同格式的调试事件:

const plusOne = computed(() => count.value + 1, {
  onTrack(e) {
    // 当 count.value 被追踪为依赖时触发
    debugger
  },
  onTrigger(e) {
    // 当 count.value 被更改时触发
    debugger
  }
})

// 访问 plusOne,会触发 onTrack
console.log(plusOne.value)

// 更改 count.value,应该会触发 onTrigger
count.value++

计算属性的 onTrack 和 onTrigger 选项仅会在开发模式下工作
3、侦听器调试

和 computed() 类似,侦听器也支持 onTrack 和 onTrigger 选项

watch(source, callback, {
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

watchEffect(callback, {
  onTrack(e) {
    debugger
  },
  onTrigger(e) {
    debugger
  }
})

侦听器的 onTrack 和 onTrigger 选项仅会在开发模式下工作

与外部状态系统集成

Vue 的响应性系统是通过深度转换普通 JavaScript 对象为响应式代理来实现的。这种深度转换在一些情况下是不必要的,在和一些外部状态管理系统集成时,甚至是需要避免的 (例如,当一个外部的解决方案也用了 Proxy 时)。

将 Vue 的响应性系统与外部状态管理方案集成的大致思路是:将外部状态放在一个 shallowRef 中。一个浅层的 ref 中只有它的 .value 属性本身被访问时才是有响应性的,而不关心它内部的值。当外部状态改变时,替换此 ref 的 .value 才会触发更新
1、不可变数据
如果你正在实现一个撤销/重做的功能,你可能想要对用户编辑时应用的状态进行快照记录。然而,如果状态树很大的话,Vue 的可变响应性系统没法很好地处理这种情况,因为在每次更新时都序列化整个状态对象对 CPU 和内存开销来说都是非常昂贵的。

不可变数据结构通过永不更改状态对象来解决这个问题。与 Vue 不同的是,它会创建一个新对象,保留旧的对象未发生改变的一部分。在 JavaScript 中有多种不同的方式来使用不可变数据,但我们推荐使用 Immer 搭配 Vue,因为它使你可以在保持原有直观、可变的语法的同时,使用不可变数据
我们可以通过一个简单的组合式函数来集成 Immer

import produce from 'immer'
import { shallowRef } from 'vue'

export function useImmer(baseState) {
  const state = shallowRef(baseState)
  const update = (updater) => {
    state.value = produce(state.value, updater)
  }

  return [state, update]
}
2、状态机
状态机是一种数据模型,用于描述应用可能处于的所有可能状态,以及从一种状态转换到另一种状态的所有可能方式。虽然对于简单的组件来说,这可能有些小题大做了,但它的确可以使得复杂的状态流更加健壮和易于管理

XState 是 JavaScript 中一个比较常用的状态机实现方案。这里是集成它的一个例子

import { createMachine, interpret } from 'xstate'
import { shallowRef } from 'vue'

export function useMachine(options) {
  const machine = createMachine(options)
  const state = shallowRef(machine.initialState)
  const service = interpret(machine)
    .onTransition((newState) => (state.value = newState))
    .start()
  const send = (event) => service.send(event)

  return [state, send]
}
3、RxJS
RxJS 是一个用于处理异步事件流的库。VueUse 库提供了 @vueuse/rxjs 扩展来支持连接 RxJS 流与 Vue 的响应性系统

标签:vue,const,进阶,onTrack,value,响应,Vue,四十二篇,debugger
From: https://www.cnblogs.com/caix-1987/p/17289987.html

相关文章

  • 第四十四篇 vue - 进阶主题 - 渲染函数 & JSX
    渲染函数&JSX在绝大多数情况下,Vue推荐使用模板语法来创建应用。然而在某些使用场景下,我们真的需要用到JavaScript完全的编程能力。这时渲染函数就派上用场了基本用法1、创建VnodesVue提供了一个h()函数用于创建vnodesimport{h}from'vue'constvnode=h(......
  • 第四十三篇 vue - 进阶主题 - 渲染机制
    渲染机制Vue是如何将一份模板转换为真实的DOM节点的,又是如何高效地更新这些节点的呢?我们接下来就将尝试通过深入研究Vue的内部渲染机制来解释这些问题虚拟DOM你可能已经听说过“虚拟DOM”的概念了,Vue的渲染系统正是基于这个概念构建的虚拟DOM(VirtualDOM,简称VDOM......
  • 第四十六篇 vue - 进阶主题 - 动画技巧
    动画技巧Vue提供了<Transition>和<TransitionGroup>组件来处理元素进入、离开和列表顺序变化的过渡效果。但除此之外,还有许多其他制作网页动画的方式在Vue应用中也适用。这里我们会探讨一些额外的技巧基于CSSclass的动画对于那些不是正在进入或离开DOM的元素,我们可......
  • 第四十五篇 vue - 进阶主题 - Vue 与 Web Components
    Vue与WebComponentsWebComponents是一组web原生API的统称,允许开发者创建可复用的自定义元素(customelements)Vue和WebComponents是互补的技术。Vue为使用和创建自定义元素提供了出色的支持。无论你是将自定义元素集成到现有的Vue应用中,还是使用Vue来构建和......
  • 第四十七篇 vue - vue2 和 vue3 的对比
    vue2和vue3不同点汇总1、生命周期2、多根节点3、CompositionApi4、异步组件5、响应式原理6、Teleport7、虚拟Dom8、事件缓存9、Diff算法优化10、打包优化11、TypeScript支持生命周期1、Vue3生命周期整体上变化不大,Vue3在大部分生命周期钩子名称......
  • 基于SpringBoot+Vue+ElementUI的在线考试系统(可做毕设)
    项目简介青云是一套麻雀虽小但五脏俱全的在线考试系统。采用了目前主流的技术栈SpringBoot+Vue+ElementUI,并进行了前后端分离。对于事务和锁都有应用,非常适合学习练手。项目演示项目演示地址:http://xuezhabiji.com:5000账号:admin密码:admin代码获取:github:https://github.com......
  • vue项目启动时 `webpack-dev-server –inline –progress –config build/webpack.dev
    vue项目在npmrundev时报错[email protected]:webpack-dev-server--inline--progress--configbuild/webpack.dev.conf.js解决这类问题主要分两种情况这个项目已经构建好的项目,你只是从git、snv或者其他地方引入,别人能运行你不能运行这是一个新构建的vue项目第一......
  • 从一个电影网站项目学习[前台显示端]—Vue.js
    本篇文章通过一个完整的电影介绍和电影资源发布网站的项目,过一遍Vue.js。通过前面章节的介绍http://www.shanhubei.com/tag/vue或在本平台下的相关文章了解一下。(ps本人是通过工具编辑器编写,同步在多个平台上)项目源码:github:https://github.com/shanhubei/vue_movie_example......
  • springboot +vue2.x实现音乐网站
    1pom文件<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache......
  • Vue进阶(四十七):面试必备:2023 Vue经典面试题总结(含答案)
    一、什么是MVVM?MVVM是Model-View-ViewModel的缩写。MVVM是一种设计思想。Model层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑;View代表UI组件,它负责将数据模型转化成UI展现出来,ViewModel是一个同步View和Model的对象。在MVVM架构下,View和Model之间并没......