effect.spec

文档直通车: https://vue3js.cn/vue-composition-api/#reactive

  1. 定义一个对象original,reactive后返回observed,得到结果两个对象的引用不能相同,observed是可响应的,original不可响应,observed得值跟original相同,从这几个特点来看,我们很容易联想到proxy,对proxy还不熟悉同学可以点proxy
  1. test('Object', () => {
  2. const original = { foo: 1 }
  3. const observed = reactive(original)
  4. expect(observed).not.toBe(original)
  5. expect(isReactive(observed)).toBe(true)
  6. expect(isReactive(original)).toBe(false)
  7. // get
  8. expect(observed.foo).toBe(1)
  9. // has
  10. expect('foo' in observed).toBe(true)
  11. // ownKeys
  12. expect(Object.keys(observed)).toEqual(['foo'])
  13. })
  1. 原型
  1. test('proto', () => {
  2. const obj = {}
  3. const reactiveObj = reactive(obj)
  4. expect(isReactive(reactiveObj)).toBe(true)
  5. // read prop of reactiveObject will cause reactiveObj[prop] to be reactive
  6. // @ts-ignore
  7. const prototype = reactiveObj['__proto__']
  8. const otherObj = { data: ['a'] }
  9. expect(isReactive(otherObj)).toBe(false)
  10. const reactiveOther = reactive(otherObj)
  11. expect(isReactive(reactiveOther)).toBe(true)
  12. expect(reactiveOther.data[0]).toBe('a')
  13. })
  1. 定义一个嵌套对象, reactive后嵌套的属性也可以响应

    1. test('nested reactives', () => {
    2. const original = {
    3. nested: {
    4. foo: 1
    5. },
    6. array: [{ bar: 2 }]
    7. }
    8. const observed = reactive(original)
    9. expect(isReactive(observed.nested)).toBe(true)
    10. expect(isReactive(observed.array)).toBe(true)
    11. expect(isReactive(observed.array[0])).toBe(true)
    12. })
  2. 观察的对象的变更会同步到原始对象

  1. test('observed value should proxy mutations to original (Object)', () => {
  2. const original: any = { foo: 1 }
  3. const observed = reactive(original)
  4. // set
  5. observed.bar = 1
  6. expect(observed.bar).toBe(1)
  7. expect(original.bar).toBe(1)
  8. // delete
  9. delete observed.foo
  10. expect('foo' in observed).toBe(false)
  11. expect('foo' in original).toBe(false)
  12. })
  1. 给observed设置一个未被观察的值可以响应,看过vue2.x的同学应该都清楚,这个在vue2.x中是不可响应的
  1. test('setting a property with an unobserved value should wrap with reactive', () => {
  2. const observed = reactive<{ foo?: object }>({})
  3. const raw = {}
  4. observed.foo = raw
  5. expect(observed.foo).not.toBe(raw)
  6. expect(isReactive(observed.foo)).toBe(true)
  7. })
  1. 观察一个已经被observed的observe应该直接返回该observe
  1. test('observing already observed value should return same Proxy', () => {
  2. const original = { foo: 1 }
  3. const observed = reactive(original)
  4. const observed2 = reactive(observed)
  5. expect(observed2).toBe(observed)
  6. })
  1. 重复观察相同的原始对象直接返回相同的proxy对象

    1. test('observing the same value multiple times should return same Proxy', () => {
    2. const original = { foo: 1 }
    3. const observed = reactive(original)
    4. const observed2 = reactive(original)
    5. expect(observed2).toBe(observed)
    6. })
  2. 不会污染原始对象

    1. test('should not pollute original object with Proxies', () => {
    2. const original: any = { foo: 1 }
    3. const original2 = { bar: 2 }
    4. const observed = reactive(original)
    5. const observed2 = reactive(original2)
    6. observed.bar = observed2
    7. expect(observed.bar).toBe(observed2)
    8. expect(original.bar).toBe(original2)
    9. })
  3. 通过toRaw api可以返回被观察对象的原始对象

  1. test('unwrap', () => {
  2. const original = { foo: 1 }
  3. const observed = reactive(original)
  4. expect(toRaw(observed)).toBe(original)
  5. expect(toRaw(original)).toBe(original)
  6. })
    1. test('should not unwrap Ref<T>', () => {
    2. const observedNumberRef = reactive(ref(1))
    3. const observedObjectRef = reactive(ref({ foo: 1 }))
    4. expect(isRef(observedNumberRef)).toBe(true)
    5. expect(isRef(observedObjectRef)).toBe(true)
    6. })
  1. test('should unwrap computed refs', () => {
  2. // readonly
  3. const a = computed(() => 1)
  4. // writable
  5. const b = computed({
  6. get: () => 1,
  7. set: () => {}
  8. })
  9. const obj = reactive({ a, b })
  10. // check type
  11. obj.a + 1
  12. obj.b + 1
  13. expect(typeof obj.a).toBe(`number`)
  14. expect(typeof obj.b).toBe(`number`)
  15. })
  1. 不能直接被观察的类型

    1. test('non-observable values', () => {
    2. const assertValue = (value: any) => {
    3. reactive(value)
    4. expect(
    5. `value cannot be made reactive: ${String(value)}`
    6. ).toHaveBeenWarnedLast()
    7. }
    8. // number
    9. assertValue(1)
    10. // string
    11. assertValue('foo')
    12. // boolean
    13. assertValue(false)
    14. // null
    15. assertValue(null)
    16. // undefined
    17. assertValue(undefined)
    18. // symbol
    19. const s = Symbol()
    20. assertValue(s)
    21. // built-ins should work and return same value
    22. const p = Promise.resolve()
    23. expect(reactive(p)).toBe(p)
    24. const r = new RegExp('')
    25. expect(reactive(r)).toBe(r)
    26. const d = new Date()
    27. expect(reactive(d)).toBe(d)
    28. })
  2. markRaw 可以给将要被观察的数据打上标记,标记原始数据不可被观察

  1. test('markRaw', () => {
  2. const obj = reactive({
  3. foo: { a: 1 },
  4. bar: markRaw({ b: 2 })
  5. })
  6. expect(isReactive(obj.foo)).toBe(true)
  7. expect(isReactive(obj.bar)).toBe(false)
  8. })
  1. 被freeze的数据不可观察
    1. test('should not observe frozen objects', () => {
    2. const obj = reactive({
    3. foo: Object.freeze({ a: 1 })
    4. })
    5. expect(isReactive(obj.foo)).toBe(false)
    6. })

shallowReactive

只为某个对象的私有(第一层)属性创建浅层的响应式代理,不会对“属性的属性”做深层次、递归地响应式代理

  1. 属性的属性不会被观察
    1. test('should not make non-reactive properties reactive', () => {
    2. const props = shallowReactive({ n: { foo: 1 } })
    3. expect(isReactive(props.n)).toBe(false)
    4. })
  1. shallowReactive后的proxy的属性再次被reactive可以被观察

    1. test('should keep reactive properties reactive', () => {
    2. const props: any = shallowReactive({ n: reactive({ foo: 1 }) })
    3. props.n = reactive({ foo: 2 })
    4. expect(isReactive(props.n)).toBe(true)
    5. })
  2. iterating 不能被观察

    1. test('should not observe when iterating', () => {
    2. const shallowSet = shallowReactive(new Set())
    3. const a = {}
    4. shallowSet.add(a)
    5. const spreadA = [...shallowSet][0]
    6. expect(isReactive(spreadA)).toBe(false)
    7. })
  3. get 到的某个属性不能被观察

  1. test('should not get reactive entry', () => {
  2. const shallowMap = shallowReactive(new Map())
  3. const a = {}
  4. const key = 'a'
  5. shallowMap.set(key, a)
  6. expect(isReactive(shallowMap.get(key))).toBe(false)
  7. })
  1. foreach 不能被观察

    1. test('should not get reactive on foreach', () => {
    2. const shallowSet = shallowReactive(new Set())
    3. const a = {}
    4. shallowSet.add(a)
    5. shallowSet.forEach(x => expect(isReactive(x)).toBe(false))
    6. })