mirror of
https://github.com/odoo/owl.git
synced 2025-10-06 19:59:41 +07:00
[REF] reactivity: new API
This commit is contained in:
committed by
Aaron Bohy
parent
10745c52d0
commit
03787cfb39
+14
-8
@@ -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
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user