经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
【Vue3响应式入门#01】Reactivity
来源:cnblogs  作者:柏成  时间:2023/10/19 10:04:00  对本文有异议

专栏分享:vue2源码专栏vue3源码专栏vue router源码专栏玩具项目专栏,硬核??推荐??

欢迎各位ITer关注点赞收藏??????

背景

以下是柏成根据Vue3官方课程整理的响应式书面文档 - 第一节,课程链接在此:Vue 3 Reactivity - Vue 3 Reactivity | Vue Mastery,本文档可作为课程的辅助材料,配合食用,快乐双倍!

我们先来看一下这个简单的Vue应用程序,Ok!如果我们加载了这个组件,然后我们的价格price发生了改变,Vue是如何知道更新模版内容的呢?接下来,我们将会用 Vue3 建造响应式的方法,从头开始制造一个响应式引擎,让我们一步一步的来解决这个问题!

dep

How can we save the total calculation, so we can run it agine when price or quantity updates ?

如何存储 total 的计算方式,当 price 或 quantities 更新时,total 再计算一次?

我们想将下面这段代码存储在某种储藏室中,然后我们需要运行它,之后我们还想再次运行这个被存储的代码【被存储可能有多种功能代码】

  1. let total = price * quantity

让我们来实现一下,下面所列举的effect()track()trigger()你都可以在 Vue3 响应性源码中看到同名的函数。

  • dep:一个 Set 对象,存储我们的effects,或者说是一个effect集(Set)。我们在这里使用 Set 的原因是 Set 不允许出现重复值,当我们尝试添加同样的effect时,它不会变成 Set 集合的两个子成员
  • effect():一个方法,包含了我们想要存储的代码
  • track():一个方法,使用dep变量去保存effect
  • trigger():一个方法,遍历dep去运行我们存储的所有代码

depsMap

Often our objects will have multiple properties and each property will need their own dep. How can we store these ?

通常,我们的对象会有多个属性,每个属性都需要自己的 Dep(依赖关系),或者说 effect 的 Set 集合,那么,我们如何存储,或者说怎样才能让每个属性都拥有自己的依赖呢?

我们现在拥有一个product对象,其每一个属性都需要有自己的dep。【dep其实就是一个effect集(Set),这个 effect集应该在值发生改变时重新运行。】

正如我们看到的,dep的类型是 Set,Set 中的每个值都只是一个我们需要执行的effect,就像我们这个计算total的匿名函数。要把这些dep存储起来,且方便我们以后在找到他们,我们要创建一个depsMap

  • depsMap: 一个 Map 对象,存储了每个属性到其自己依赖dep对象的映射;每一个属性都拥有它们自己的,可以重新运行effectdep;我们使用对象属性名作为键,比如pricequantity,值是一个depeffect集】

让我们来实现一下,代码如下:

  1. <html>
  2. <head></head>
  3. <body>
  4. <div id="app">
  5. <div>depsMap</div>
  6. </div>
  7. </body>
  8. <script>
  9. const depsMap = new Map()
  10. // Save this code
  11. function track(key) {
  12. let dep = depsMap.get(key) // Get the dep for this property
  13. if (!dep) {
  14. depsMap.set(key, (dep = new Set())) // No dep yet, so let's create one
  15. }
  16. dep.add(effect) // Add this effect Since it's a set, it won't add the effect again if it already exists
  17. }
  18. // Run all the code I've saved
  19. function trigger(key) {
  20. let dep = depsMap.get(key) // Get the dep for the key
  21. if (dep) {
  22. dep.forEach(effect => {
  23. effect() // If it exists, run each effect
  24. })
  25. }
  26. }
  27. let product = {
  28. price: 5,
  29. quantity: 2,
  30. }
  31. let total = 0
  32. let effect = () => {
  33. total = product.price * product.quantity
  34. }
  35. track('quantity')
  36. effect()
  37. </script>
  38. </html>

当我们触发函数trigger('quantity')effect就运行了;控制台输出结果如下:

现在我们就对 对象中的不同属性 有了一种跟踪依赖关系的方法

targetMap

What if we have multiple reactive objects that each need to track effects ?

如果我们有多个响应式对象,每个响应式对象属性都需要存储 effect 呢?例如?

  1. let product = { price: 5, quantity: 2 }
  2. let user = { name: "burc", age: 18 }

到目前为止,我们有一张 depsMap,它存储了每个属性自己的依赖对象(属性到自己依赖对象的映射)。然后每个属性都拥有它们自己的并可以重新运行effectdep

我们这里需要一个其他对象,即 targetMap 。它的键以某种方式引用了我们的响应性对象,例如productuser

  • targetMap: 一个 WeakMap 对象,它储存了与每个 响应性对象属性 关联的依赖,在 Vue3 中,它被称为目标图
  • WeakMap: 与 Map 结构类似,但只接受对象作为键名(null除外),不接受其他类型的值作为键名

用一个简单的例子告诉我们 WeakMap 是如何工作的,如想了解详细API请移步 阮一峰ES6文档-WeakMap

  1. let product = { price: 5, quantity: 2 }
  2. const targetMap = new WeakMap()
  3. targetMap.set(product, "example code to test")
  4. console.log(targetMap.get(product))
  5. //"example code to test"

让我们来实现一下,代码如下:

  1. <html>
  2. <head></head>
  3. <body>
  4. <div id="app">
  5. <div>targetMap</div>
  6. </div>
  7. </body>
  8. <script>
  9. const targetMap = new WeakMap() // For storing the dependencies for each reactive object
  10. // Save this code
  11. function track(target, key) {
  12. let depsMap = targetMap.get(target) // Get the current depsMap for this target(reactive object - product)
  13. if (!depsMap) {
  14. targetMap.set(target, (depsMap = new Map())) // If it doesn't exist, create it
  15. }
  16. let dep = depsMap.get(key) // Get the dependency object for this peoperty - quantity
  17. if (!dep) {
  18. depsMap.set(key, (dep = new Set())) // If it doesn't exist, create it
  19. }
  20. dep.add(effect) // Add the effect to the dependency
  21. }
  22. // Run all the code I've saved
  23. function trigger(target, key) {
  24. const depsMap = targetMap.get(target) // Does this object have any properties that have dependencies?
  25. if (!depsMap) {
  26. return // If no, return from the function immediately
  27. }
  28. let dep = depsMap.get(key) // Otherwise, check if this property has a dependency
  29. if (dep) {
  30. dep.forEach(effect => {
  31. effect()
  32. }) // Run those
  33. }
  34. }
  35. let product = { price: 5, quantity: 2 }
  36. let total = 0
  37. let effect = () => {
  38. total = product.price * product.quantity
  39. }
  40. track(product, 'quantity')
  41. effect()
  42. </script>
  43. </html>

当我们触发函数 trigger(product, 'quantity')effect就运行了;控制台输出结果如下:

diagram

让我们再分析概括一下图表

  • targetMap:存储了每个 响应性对象属性 关联的依赖;类型是 WeakMap
  • depsMap:存储了每个属性的依赖;类型是 Map
  • dep:存储了我们的effects,一个effects集,这些effect在值发生变化时重新运行;类型是 Set

Now!我们就实现了一种储存不同effect的方法,但是我们还没有办法让我们的effect自动重新运行。这是第二个重要的部分,将在下一篇文章讲解!

原文链接:https://www.cnblogs.com/burc/p/17769969.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号