Skip to content

reactive

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

通过 toRaw “解包”,类似 unref

1 递归 reactive

reactive 递归 遍历 target 的属性,当属性值为一个对象或数组时,会将该属性值也转换为 reactive

js
import { reactive, isReactive } from 'vue'

const info = reactive({
  name: 'Jack',
  father: {
    name: 'Tom'
  },
  friends: ['Marry', 'Bob']
})

Object.keys(obj).forEach(item => {
  console.log(item, isReactive(obj[item]), obj[item])
})

// 打印:
// name false Jack
// father true Proxy {name: 'Tom'}
// friends true Proxy {0: 'Marry', 1: 'Bob'}

若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive() 作替代。(注意区别单词 shallow 和 shadow,前者表示浅的,后者表示阴影)

2 递归解包

reactive 也将递归解包所有 ref 的属性

js
import { ref, reactive } from 'vue'

const city = ref('sz')

const info = reactive({
  // 写法1
  city: city.value,
  // 写法2
  //city: city
})
console.log(info.city)

上面两种写法是有区别的,对于写法1,cityinfo.city 没有连写,任何一个改变,不影响另外一个,写法2则相反,cityinfo.city 有联系,改变一个,另外一个也改变。

3 简版手写

js
// 定义一个reactive函数,传入一个目标对象
function reactive(target) {
  // 判断当前的目标对象是不是object类型(对象/数组)
  if (target && typeof target === 'object') {
    // 对数组或者是对象中所有的数据进行reactive的递归处理
    // 先判断当前的数据是不是数组
    if (Array.isArray(target)) {
      // 数组的数据要进行遍历操作0
      target.forEach((item, index) => {
        // 如果数组中还有数组
        // 使用递归
        target[index] = reactive(item);
      });
    } else {
      // 再判断当前的数据是不是对象
      // 对象的数据也要进行遍历的操作
      Object.keys(target).forEach(key => {
        target[key] = reactive(target[key]);
      });
    }
    return new Proxy(target, reactiveHandler);
  }
  // 如果传入的数据是基本类型的数据,那么就直接返回
  return target;
}

// 定义一个reactiveHandler处理对象
const reactiveHandler = {
  // 获取属性值
  get(target, prop) {
    if (prop === '_is_reactive') return true;
    const result = Reflect.get(target, prop);
    console.log('拦截了读取数据', prop, result);
    return result;
  },
  // 修改属性值或者是添加属性
  set(target, prop, value) {
    const result = Reflect.set(target, prop, value);
    console.log('拦截了修改数据或者是添加属性', prop, value);
    return result;
  },
  // 删除某个属性
  deleteProperty(target, prop) {
    const result = Reflect.deleteProperty(target, prop);
    console.log('拦截了删除数据', prop);
    return result;
  }
}