[REF] reactivity: new API

This commit is contained in:
Mathieu Duckerts-Antoine
2021-11-15 16:56:50 +01:00
committed by Aaron Bohy
parent 10745c52d0
commit 03787cfb39
2 changed files with 30 additions and 35 deletions
+14 -8
View File
@@ -14,11 +14,20 @@ const KEYS = Symbol("keys");
const ROOT = Symbol("root"); const ROOT = Symbol("root");
const SEED = Symbol("Seed"); const SEED = Symbol("Seed");
export function atom(source: any, observer: Observer) { export function observe(source: any, observer: Observer): [Atom, Function] {
if (!isTrackable(source)) {
throw new Error("First argument is not trackable");
}
const unregisterObserver = registerObserver(observer);
const newAtom = atom(source, observer);
return [newAtom, unregisterObserver];
}
function atom(source: any, observer: Observer) {
return _atom(source, observer, true); return _atom(source, observer, true);
} }
export function _atom(source: any, observer: Observer, seed = false) { function _atom(source: any, observer: Observer, seed = false) {
if (isTrackable(source) && observerSourceAtom.has(observer)) { if (isTrackable(source) && observerSourceAtom.has(observer)) {
source = (source as any)[SOURCE] || source; source = (source as any)[SOURCE] || source;
const oldAtom = observerSourceAtom.get(observer)!.get(source); const oldAtom = observerSourceAtom.get(observer)!.get(source);
@@ -123,7 +132,7 @@ function isTrackable(value: any): boolean {
); );
} }
export function registerObserver(observer: Observer) { function registerObserver(observer: Observer) {
if (!observerSourceAtom.get(observer)) { if (!observerSourceAtom.get(observer)) {
observerSourceAtom.set(observer, new Map()); observerSourceAtom.set(observer, new Map());
} }
@@ -149,13 +158,10 @@ function unregisterObserverAtoms(observer: Observer, keepSeeds: boolean) {
} }
export function useState(state: any): Atom { export function useState(state: any): Atom {
if (!isTrackable(state)) {
throw new Error("Argument is not trackable");
}
const node = getCurrent()!; const node = getCurrent()!;
const unregisterObserver = registerObserver(node); const [newAtom, unregisterObserver] = observe(state, node);
onWillUnmount(() => unregisterObserver()); onWillUnmount(() => unregisterObserver());
return atom(state, node); return newAtom;
} }
class ObserverSet { class ObserverSet {
+16 -27
View File
@@ -1,5 +1,5 @@
import { Component, mount, onRender, onWillStart, onWillUpdateProps, useState } from "../src"; import { Component, mount, onRender, onWillStart, onWillUpdateProps } from "../src";
import { atom, registerObserver } from "../src/reactivity"; import { observe, useState } from "../src/reactivity";
import { xml } from "../src/tags"; import { xml } from "../src/tags";
import { import {
makeDeferred, makeDeferred,
@@ -9,10 +9,9 @@ import {
snapshotEverything, snapshotEverything,
} from "./helpers"; } from "./helpers";
function createAtom(value: any, observer?: any) { function createAtom(value: any, observer: any = () => {}) {
observer = observer || (() => {}); const [atom] = observe(value, observer);
registerObserver(observer); return atom;
return atom(value, observer);
} }
describe("Reactivity: atom", () => { describe("Reactivity: atom", () => {
@@ -54,15 +53,8 @@ describe("Reactivity: atom", () => {
expect(Array.isArray(atom1)).toBe(true); expect(Array.isArray(atom1)).toBe(true);
}); });
test("return value if not proxifiable", () => { test("Throw error if value is not proxifiable", () => {
const atom1 = createAtom(1); expect(() => createAtom(1)).toThrow("First argument is not trackable");
expect(atom1).toBe(1);
});
test("return value if observer is not registered", () => {
const obj = { a: 1 };
const atom1 = atom(obj, () => {});
expect(atom1).toBe(obj);
}); });
test("atom observer is called properly", async () => { test("atom observer is called properly", async () => {
@@ -270,16 +262,16 @@ describe("Reactivity: atom", () => {
}); });
test("immediately returns primitive values", () => { test("immediately returns primitive values", () => {
expect(createAtom(1)).toBe(1); expect(() => createAtom(1)).toThrowError();
expect(createAtom("asf")).toBe("asf"); expect(() => createAtom("asf")).toThrowError();
expect(createAtom(true)).toBe(true); expect(() => createAtom(true)).toThrowError();
expect(createAtom(null)).toBe(null); expect(() => createAtom(null)).toThrowError();
expect(createAtom(undefined)).toBe(undefined); expect(() => createAtom(undefined)).toThrowError();
}); });
test("immediately returns dates", () => { test("immediately returns dates", () => {
const date = new Date(); const date = new Date();
expect(createAtom(date)).toBe(date); expect(() => createAtom(date)).toThrow("First argument is not trackable");
}); });
test("can observe object with some key set to null", async () => { test("can observe object with some key set to null", async () => {
@@ -294,8 +286,7 @@ describe("Reactivity: atom", () => {
test("can reobserve object with some key set to null", async () => { test("can reobserve object with some key set to null", async () => {
let n = 0; let n = 0;
const fn = () => n++; const fn = () => n++;
const unregisterObserver = registerObserver(fn); const [atom1, unregisterObserver] = observe({ a: { b: null } } as any, fn);
const atom1 = createAtom({ a: { b: null } } as any, fn);
const atom2 = createAtom(atom1, fn); const atom2 = createAtom(atom1, fn);
expect(atom2).toBe(atom1); expect(atom2).toBe(atom1);
expect(atom2).toEqual(atom1); expect(atom2).toEqual(atom1);
@@ -846,9 +837,8 @@ describe("Reactivity: atom", () => {
test("can unobserve a value", async () => { test("can unobserve a value", async () => {
let n = 0; let n = 0;
const cb = () => n++; const cb = () => n++;
const unregisterObserver = registerObserver(cb);
const atom1 = createAtom({ a: 1 }, cb); const [atom1, unregisterObserver] = observe({ a: 1 }, cb);
atom1.a = atom1.a + 3; atom1.a = atom1.a + 3;
await nextMicroTick(); await nextMicroTick();
@@ -932,8 +922,7 @@ describe("Reactivity: atom", () => {
test("notification is not done after unregistration", async () => { test("notification is not done after unregistration", async () => {
let n = 0; let n = 0;
const observer = () => n++; const observer = () => n++;
const unregisterObserver = registerObserver(observer); const [state, unregisterObserver] = observe({ a: 1 } as any, observer);
const state = atom({ a: 1 } as any, observer);
state.a = state.a; state.a = state.a;
await nextMicroTick(); await nextMicroTick();