From f26ff7918fe9a3747172929e6262cdc396f0cc1a Mon Sep 17 00:00:00 2001 From: cuixiaorui Date: Tue, 17 Aug 2021 21:36:51 +0800 Subject: [PATCH] feat: ref --- src/reactivity/__tests__/ref.spec.ts | 35 +++++++++++++++++ src/reactivity/src/effect.ts | 4 +- src/reactivity/src/ref.ts | 58 ++++++++++++++++++++++++++++ src/shared/index.ts | 6 ++- 4 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 src/reactivity/__tests__/ref.spec.ts create mode 100644 src/reactivity/src/ref.ts diff --git a/src/reactivity/__tests__/ref.spec.ts b/src/reactivity/__tests__/ref.spec.ts new file mode 100644 index 0000000..80d508b --- /dev/null +++ b/src/reactivity/__tests__/ref.spec.ts @@ -0,0 +1,35 @@ +import { effect } from "../src/effect"; +import { ref } from "../src/ref"; +describe("ref", () => { + it("should be reactive", () => { + const a = ref(1); + let dummy; + let calls = 0; + effect(() => { + calls++; + dummy = a.value; + }); + expect(calls).toBe(1); + expect(dummy).toBe(1); + a.value = 2; + expect(calls).toBe(2); + expect(dummy).toBe(2); + // same value should not trigger + a.value = 2; + expect(calls).toBe(2); + expect(dummy).toBe(2); + }); + + it("should make nested properties reactive", () => { + const a = ref({ + count: 1, + }); + let dummy; + effect(() => { + dummy = a.value.count; + }); + expect(dummy).toBe(1); + a.value.count = 2; + expect(dummy).toBe(2); + }); +}); diff --git a/src/reactivity/src/effect.ts b/src/reactivity/src/effect.ts index 7b7291b..453b06f 100644 --- a/src/reactivity/src/effect.ts +++ b/src/reactivity/src/effect.ts @@ -77,7 +77,7 @@ export function track(target, type, key) { trackEffects(dep); } -function trackEffects(dep) { +export function trackEffects(dep) { // 用 dep 来存放所有的 effect dep.add(activeEffect); (activeEffect as any).deps.push(dep); @@ -108,7 +108,7 @@ export function trigger(target, type, key) { triggerEffects(createDep(effects)); } -function triggerEffects(dep) { +export function triggerEffects(dep) { // 执行收集到的所有的 effect 的 run 方法 for (const effect of dep) { if (effect.scheduler) { diff --git a/src/reactivity/src/ref.ts b/src/reactivity/src/ref.ts new file mode 100644 index 0000000..b2398f6 --- /dev/null +++ b/src/reactivity/src/ref.ts @@ -0,0 +1,58 @@ +import { trackEffects, triggerEffects } from "./effect"; +import { createDep } from "./dep"; +import { isObject, hasChanged } from "../../shared"; +import { reactive } from "./reactive"; + +export class RefImpl { + private _rawValue: any; + private _value: any; + public dep; + + constructor(value) { + this._rawValue = value; + // 看看value 是不是一个对象,如果是一个对象的话 + // 那么需要用 reactive 包裹一下 + this._value = convert(value); + this.dep = createDep(); + } + + get value() { + // 收集依赖 + trackRefValue(this); + return this._value; + } + + set value(newValue) { + // 当新的值不等于老的值的话, + // 那么才需要触发依赖 + if (hasChanged(newValue, this._rawValue)) { + // 更新值 + this._value = convert(newValue); + this._rawValue = newValue; + // 触发依赖 + triggerRefValue(this); + } + } +} + +export function ref(value) { + return createRef(value); +} + +function convert(value) { + return isObject(value) ? reactive(value) : value; +} + +function createRef(value) { + const refImpl = new RefImpl(value); + + return refImpl; +} + +function triggerRefValue(ref) { + triggerEffects(ref.dep); +} + +function trackRefValue(ref) { + trackEffects(ref.dep); +} diff --git a/src/shared/index.ts b/src/shared/index.ts index 6d6f935..0a425aa 100644 --- a/src/shared/index.ts +++ b/src/shared/index.ts @@ -13,7 +13,11 @@ export const camelize = (str: string): string => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : "")); }; -export const extend = Object.assign +export const extend = Object.assign; + +export function hasChanged(value, oldValue) { + return !Object.is(value, oldValue); +} /** * @private