《Vue进阶教程》第四课:reactive()函数详解

发布于:2024-12-18 ⋅ 阅读:(108) ⋅ 点赞:(0)

  往期内容:

《Vue零基础入门教程》合集(完结)

《Vue进阶教程》第一课:什么是组合式API

《Vue进阶教程》第二课:为什么提出组合式API

《Vue进阶教程》第三课:Vue响应式原理

通过前面的学习, 我们了解到reactive可以将一个普通对象转换成响应式对象.

那么, 接下来我们就详细研究一下这个函数.

研究函数主要从这样三个方面

  1. 输入, 也就是参数
  2. 作用, 做了什么
  3. 输出, 也就是返回值
  1. 参数: 只能是引用类型数据, 不能是值类型数据
  2. 作用: 创建传入对象的深层代理, 并返回代理后的对象
  3. 返回值: 一个Proxy代理对象

1) 深层代理

不管传入的对象存在多少层嵌套(对象套对象的情况), 每一层都具有响应性

示例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../node_modules/vue/dist/vue.global.js"></script>
  </head>
  <body>
    <script>
      const { reactive, effect } = Vue

      const pState = reactive({
        name: 'xiaoming',
        age: 20,
        gf: {
          name: 'xiaomei',
          city: {
            name: 'wuhan',
          },
        },
      })

      effect(() => {
        console.log(
          `${pState.name}的女朋友叫${pState.gf.name}, 在${pState.gf.city.name}`
        )
      })

      setTimeout(() => {
        console.log('过了一段时间, 她去了beijing')
        // 不管嵌套多少层, 都具有响应性
        pState.gf.city.name = 'beijing'
      }, 1000)
    </script>
  </body>
</html>

2) 重复代理

  1. 对同一个普通对象, 多次代理, 返回的结果唯一
  2. 对代理后的对象再次代理, 返回的结果唯一

以上, 可以理解为单例模式, reactive创建的代理对象只会存在一个

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../node_modules/vue/dist/vue.global.js"></script>
  </head>
  <body>
    <script>
      const { reactive, effect } = Vue

      const state = { name: 'xiaoming' }
      const p1 = reactive(state)
      const p2 = reactive(state)
      // 对同一个对象多次代理, 返回的结果唯一
      console.log(p1 === p2) // true

      const p3 = reactive(p1)
      // 对代理后的对象, 再次代理, 返回的结果唯一
      console.log(p3 === p1) // true
    </script>
  </body>
</html>

3) 局限性

  1. 传入参数只能是对象
  2. 解构或者赋值操作会丢失响应性

示例1

解构赋值后的变量没有响应性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../node_modules/vue/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const { reactive, effect } = Vue

      const pState = reactive({ name: 'xiaoming' })
      // 对代理对象进行解构
      let { name } = pState

      effect(() => {
        app.innerHTML = pState.name
      })

      setTimeout(() => {
        name = 'xiaomei'
        console.log('对解构后的name操作, 不会触发响应式')
      }, 1000)
    </script>
  </body>
</html>

示例2

赋值操作丢失响应性

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../node_modules/vue/dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const { reactive, effect } = Vue

      let todos = reactive([])

      effect(() => {
        app.innerHTML = JSON.stringify(todos)
      })

      // 模拟向接口请求
      setTimeout(() => {
        // 将接口返回的数据赋值给todos, 导致todos丢失了响应性
        todos = [
          { id: 1, content: 'todo-1' },
          { id: 2, content: 'todo-2' },
        ]
      }, 1000)
    </script>
  </body>
</html>


网站公告

今日签到

点亮在社区的每一天
去签到