13.实现reactive和readonly嵌套对象转换功能

97 阅读1分钟

一、单元测试编写 对于嵌套的对象数据结构,也需要是响应式。reactive嵌套对象测试代码如下:

test("nested reactive", () => {
    const original = {
      nested: {
        foo: 1,
      },
      array: [{bar: 2}],
    }
    const observed = reactive(original);
    expect(isReactive(observed.nested)).toBe(true);
    expect(isReactive(observed.array)).toBe(true);
    expect(isReactive(observed.array[0])).toBe(true);
})

而readonly嵌套对象测试则在原来测试代码上加上2行即可

it("happy path", () => {
    // not set
    const original = {foo: 1,bar: {baz: 2}};
    const wrapped = readonly(original);
    expect(wrapped).not.toBe(original);
    expect(isReadonly(wrapped)).toBe(true);
    //新增
    expect(isReadonly(wrapped.bar)).toBe(true);
    //新增
    expect(isReadonly(original.bar)).toBe(false);
    expect(wrapped.foo).toBe(1)
  })

二、代码功能实现 在原有基础上新增是否是对象的判断,是则判断是否只读,不是只读则调用reactive将其变为响应式。 src/reactivity/baseHandlers.ts

import {track, trigger} from "./effect";
import { ReactiveFlags,reactive,readonly} from "./reactive";
//新增
import {isObject} from "../shared/index"

const get = createGetter();
const set = createSetter();
const readonlyGet = createGetter(true)

function createGetter(isReadonly = false){
  return function get(target,key){
    if(key === ReactiveFlags.IS_REACTIVE){
      return !isReadonly;
    } else if (key === ReactiveFlags.IS_READONLY){
      return isReadonly;
    }
    const res = Reflect.get(target,key);
    // 新增,看看res是不是object
    if(isObject(res)){
      return isReadonly? readonly(res) : reactive(res)
    }
    if(!isReadonly){
      track(target,key)
    }
    return res;
  }
}
function createSetter (){
  return function set (target, key, value) {
    const res = Reflect.set(target, key, value);
    trigger(target, key);
    return res;
  }
}
export const mutableHandler = {
  get,
  set
}

export const readonlyHandlers = {
  get:readonlyGet,
  set(target,key,value){
    console.warn('key:${key} set 失败,因为 target 是 readonly',target)
    return true;
  }
}

其中isObject判断方法如下 src/sahred/index.ts

export const extend = Object.assign;
新增
export const isObject = (val) => {
  return val !== null && typeof val === "object";
}

三、执行测试

执行测试脚本,测试通过

yarn test reactive