{console.warn=vi.fn();constoriginal={foo:1,};constobserved=readonly({foo:1,});expect(original) . not.toBe(observed);expect(observed.foo).toBe(1);//set가 작동하지 않습니다."/> {console.warn=vi.fn();constoriginal={foo:1,};constobserved=readonly({foo:1,});expect(original) . not.toBe(observed);expect(observed.foo).toBe(1);//set가 작동하지 않습니다.">

 >  기사  >  웹 프론트엔드  >  vue3에서 반응적으로 읽기 전용을 구현하는 방법은 무엇입니까

vue3에서 반응적으로 읽기 전용을 구현하는 방법은 무엇입니까

WBOY
WBOY앞으로
2023-05-20 22:19:221481검색

readonly

it("happy path", () => {
    console.warn = vi.fn();
    const original = {
      foo: 1,
    };
    const observed = readonly({
      foo: 1,
    });
    expect(original).not.toBe(observed);
    expect(observed.foo).toBe(1);
    //  set不起作用
    observed.foo = 2; 
    expect(observed.foo).toBe(1);
    //  当被set的时候,发出一个警告
    expect(console.warn).toBeCalled();
  });

의 구현은 실제로 이전의 reactive 구현과 매우 유사합니다. 차이점은 set가 사용될 때 트리거가 트리거되지 않지만 경고가 발생한다는 것입니다. . 물론 변경되지 않으므로 track은 필요하지 않습니다. reactive 十分的类似,区别只不过是set 的时候不要触发trigger,而是警告。当然既然是不会被改变的,track 也是不必要的。

export function readonly(raw) { 
    return new Proxy(raw, { 
        get(target, key) { 
            const res = Reflect.get(target, key); 
            return res; 
        }, 
        set(target, key, newValue, receiver) {
            console.warn(
              `property: ${String(key)} can't be set, beacase ${target} is readonly.`
            );
            return true;
      },
    }); 
}
export function reactive(raw) { 
    return new Proxy(raw, { 
        get(target, key) { 
            const res = Reflect.get(target, key); 
            // 依赖收集 
            track(target, key); 
            return res; 
        }, 
        set(target, key, value) { 
            const res = Reflect.set(target, key, value); 
            // 触发依赖 
            trigger(target, key); 
            return res; 
        }, 
    }); 
}

重构

可以看到,readonlyreactive 实现其实很类似,那我们可以重构一下,增强后续的拓展性。

至于我说的类似,指的是 new Proxy(target, handlers) 中的handlers(处理器对象)中的一些traps(捕获器)。即get, set 这些方法。

我们可以通过工厂函数来创建那些traps函数,来简化我们的代码,提高可维护性。

另外,我们假定traps可以有工厂可以生产了,即handlers这部分相当于被定下来了,new Proxy 这部分也理应可以通过工厂函数创造出来。

我们先抽出一个公共的文件 baseHandler.ts

//  baseHanlder.ts
import { track, trigger } from "./effect";
//  get的工厂函数
function createGetter(isReadonly = false) {
  return function get(target, key) {
    const res = Reflect.get(target, key);
    if (!isReadonly) {
      track(target, key);
    }
    return res;
  };
}
function createSetter() {
  return function set(target, key, newValue, receiver) {
    const res = Reflect.set(target, key, newValue, receiver);
    trigger(target, key, type, newValue);
    return res;
  };
}
export const mutableHandler = {
  get: createGetter(),
  set: createSetter(),
};
export const readonlyHandler = {
  get: createGetter(),
  set(target, key, newValue, receiver) {
    console.warn(
      `property: ${String(key)} can't be set, beacase ${target} is readonly.`
    );
    return true;
};

然后是我们的reactive.ts

//  reactive.ts
import {
  mutableHandler,
  readonlyHandler,
} from "./baseHandlers";
//  proxy的工厂函数
function createReactiveObject(
  target,
  baseHandlers: ProxyHandler<any>
) {
  return new Proxy(target, baseHandlers);
}
export function reactive(target) {
  return createReactiveObject(target, mutableHandler);
}
export function readonly(target) {
  return createReactiveObject(target, readonlyHandler);
}

Refactoring🎜🎜 readonlyreactive의 구현이 실제로 매우 유사하다는 것을 알 수 있으므로 리팩터링하여 후속 확장성을 향상할 수 있습니다. 🎜🎜내가 말한 것과 비슷하다는 것은 new Proxy(target, handlers)의 핸들러(프로세서 개체)에 있는 일부 트랩(캡처러)을 의미합니다. 즉, 이러한 메소드를 get, set합니다. 🎜🎜팩토리 함수를 통해 트랩 함수를 생성하여 코드를 단순화하고 유지 관리성을 향상시킬 수 있습니다. 🎜🎜또한 트랩은 팩토리에서 생성할 수 있다고 가정합니다. 즉 핸들러 부분은 결정되는 것과 동일하며 새 프록시 부분도 팩토리 함수를 통해 생성되어야 합니다. 🎜🎜먼저 공개 파일 baseHandler.ts🎜rrreee🎜를 추출한 다음 reactive.ts🎜rrreee를 추출합니다.

위 내용은 vue3에서 반응적으로 읽기 전용을 구현하는 방법은 무엇입니까의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제