re-js / reactive-box Goto Github PK
View Code? Open in Web Editor NEW1 kB effective reactive core
License: MIT License
1 kB effective reactive core
License: MIT License
test("should safe correct reactions order for changing depth without modification", () => {
const spy = jest.fn();
const a = mut(0);
const b = mut(0);
const m0 = comp(() => {
return !b.val ? a.val : k0.val;
});
const k0 = comp(() => {
return !b.val ? m0.val : a.val;
});
const m = comp(() => m0.val);
const k = comp(() => k0.val);
let i = 0;
run(() => (k.val, spy('k', i++)));
run(() => (m.val, spy('m', i++)));
expect(spy).toHaveBeenNthCalledWith(1, 'k', 0);
expect(spy).toHaveBeenNthCalledWith(2, 'm', 1);
expect(spy).toBeCalledTimes(2);
spy.mockReset();
a.val = 1;
expect(spy).toHaveBeenNthCalledWith(1, 'm', 2);
expect(spy).toHaveBeenNthCalledWith(2, 'k', 3);
expect(spy).toBeCalledTimes(2);
spy.mockReset();
// switch
b.val = 1;
expect(spy).toBeCalledTimes(0);
// check
a.val = 2;
// TODO: check failed (m:4, k:5)
// expect(spy).toHaveBeenNthCalledWith(1, 'k', 4);
// expect(spy).toHaveBeenNthCalledWith(2, 'm', 5);
expect(spy).toBeCalledTimes(2);
spy.mockReset();
});
d80be9c#diff-a9b84960a146958d9aecb5cbe3fccdf262c40fe07bddbb659f63d8a7766ed3a5R203-R245
These are three basic elements necessary for creating data flow any difficulty.
The first element is a reactive container for an immutable value. All reactions beginning from container change value reaction.
The second one is the middle element. It uses all reactive containers as a source of values and returns the result of the expression. It's a transformer set of reactive values to a single one. The selector can be used as a reactive container in other selectors and expressions.
It subscribes to change in any of the dependencies. And will recalculate the value if some of the dependency changed.
And the last one is a reaction subscriber. It provides the possibility to subscribe to change any set of reactive containers. It can be run again after the listener was called.
Necessary to create breakable flow, who can stop the flow of data spread, and rerun it as many times as necessary.
flow((stop?, resolve?, prev_value?) => {}, empty_value?, compare_fn?);
Example of using:
// Awaiting flow
const b = box(0);
const f = flow((stop, resolve) => {
const v = b[0]();
setTimeout(() => resolve(v));
return stop;
});
expr(() => {
console.log(b[0](), f[0]());
})[0]();
b[1](1);
// 0, undefined
// 1, undefined
// 1, 0
// 1, 1
Or multiple resolves in one time
const b = box(0);
const f = flow((stop, resolve) => {
const v = b[0]();
for (let i = 0; i < v; i++) resolve(i);
return 0;
});
expr(() => {
console.log(b[0](), f[0]());
})[0]();
b[1](3);
// 0, 0
// 3, 0
// 3, 1
// 3, 2
// 3, 0
And transaction support:
const b = box(0);
const f = flow((stop, resolve) => {
const v = b[0]();
const commit = transaction();
for (let i = 0; i < v; i++) resolve(i);
commit();
return stop;
});
expr(() => {
console.log(b[0](), f[0]());
})[0]();
b[1](3);
// 0, 0
// 3, 2
Result caching similar selector
const a = box(0);
let i = 0;
const f = flow(() => (i++, a[0]() + 1));
assert(i == 1);
assert(f[0]() == 1);
assert(f[0]() == 1);
assert(i == 1);
a[1](1);
assert(i == 2);
assert(f[0]() == 2);
assert(i == 2);
For performance reason necessary to change invalidation propagate strategy for a selector.
If the selector has holders, I need to recalculate It early, before expanding dependencies after the sync updaters phase.
If the value of the selector is not changed, not need to propagate invalidation to its holders.
[] Add transaction
const [a, b] = [box(0), box[0]];
const commit = transaction();
a[1](10);
b[1](11);
commit();
[] Make jsx with box value support
const name = box('');
const App = () => <h1>{name}</h1>
const [get_a, set_a] = box(-5);
const [get, free] = flow(init_value?, (stop) => {
// stop is only function, and returns void, no throw anything
if (get_a() > 0) stop();
return get_a() + 1;
});
get() // -4
set_a(0);
get() // 1;
set_a(5);
get() // 1;
Necessary to add a free function for the box. The source problem is subscriptions in the cycle, the decision of that free box after each iteration.
const [get_a, set_a, free_a] = box(0);
expr(() => {
console.log(get_a());
})[0]();
set_a(1);
free_a();
set_a(2);
// 0
// 1
test("write and read selector in write phase", () => {
const spy = jest.fn();
const a = mut(0);
const b = mut(1);
const s_1 = comp(() => b.val + 1);
const s_2 = comp(() => s_1.val + 1);
const s_3 = comp(() => s_2.val + 1);
const e = expr(() => {
if (a.val > 0) {
b.val = a.val + 1;
spy(s_3.val);
}
});
e[0]();
expect(s_3.val).toBe(4);
a.val = 1;
expect(spy).toBeCalledTimes(2);
expect(spy).toHaveBeenNthCalledWith(1, 4); // TODO: that call possible to exclude
expect(spy).toHaveBeenNthCalledWith(2, 5);
});
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.