nesquick 0.0.27 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/lib/NesquickComponent.js +5 -5
- package/lib/State.js +78 -22
- package/lib/types/State.d.ts +10 -5
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
### Motivation
|
|
2
|
+
I like react, but it always bugged me how you need to create a full fake DOM that is going to be compared to a virtual DOM to finally render the updates in the browser. Yes, it will only update the real DOM with the new changes, but the process of creating a full fake DOM and comparing it each time something is updated is incredibly resource wasting. I always thought in a way to link states to HTML elementos directly, so no more virtual DOM is needed, and like so, **N**imble **E**element **S**uper **Quick** (`nesquick`) was born. At first it required for you to define the *subscribers*, so if you forgot to create a subscriber, no state will be linked to an HTML property. Now, with the magic of Typescript, you can link states to HTML elements without taking care of the subscribers, which makes it easier. For example, this is `nesquick`:
|
|
3
|
+
```ts
|
|
4
|
+
import { useState } from "nesquick";
|
|
5
|
+
|
|
6
|
+
function MyComp() {
|
|
7
|
+
const [ getNumber, setNumber ] = useState(0);
|
|
8
|
+
return <div>
|
|
9
|
+
<button onClick={() => setNumber(Date.now())}>Update number</button>
|
|
10
|
+
<div>Number: {getNumber()}</div>
|
|
11
|
+
</div>;
|
|
12
|
+
}
|
|
13
|
+
```
|
|
14
|
+
Pretty straightforward. States have getters and setters, and that's it. With this approach, no more virtual DOM is needed.
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
Just `npm install nesquick`.
|
|
18
|
+
|
|
19
|
+
[WIP]
|
package/lib/NesquickComponent.js
CHANGED
|
@@ -161,7 +161,7 @@ class NesquickComponent {
|
|
|
161
161
|
_renderStyle(element, style) {
|
|
162
162
|
switch (typeof style) {
|
|
163
163
|
case "function": {
|
|
164
|
-
(0, State_1.useRender)(style, (style,
|
|
164
|
+
(0, State_1.useRender)(style, (style, lastReaction) => {
|
|
165
165
|
if (this._styleSubscriptions != null) {
|
|
166
166
|
this._styleSubscriptions.dispose();
|
|
167
167
|
this._styleSubscriptions = null;
|
|
@@ -169,16 +169,16 @@ class NesquickComponent {
|
|
|
169
169
|
switch (typeof style) {
|
|
170
170
|
case "object": {
|
|
171
171
|
if (style) {
|
|
172
|
-
if (
|
|
172
|
+
if (lastReaction) {
|
|
173
|
+
this._renderStyles(element, style);
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
173
176
|
element.removeAttribute("style");
|
|
174
177
|
this._styleSubscriptions = new State_1.Subscriptions();
|
|
175
178
|
State_1.subscriptions.set(this._styleSubscriptions);
|
|
176
179
|
this._renderStyles(element, style);
|
|
177
180
|
State_1.subscriptions.reset();
|
|
178
181
|
}
|
|
179
|
-
else {
|
|
180
|
-
this._renderStyles(element, style);
|
|
181
|
-
}
|
|
182
182
|
}
|
|
183
183
|
break;
|
|
184
184
|
}
|
package/lib/State.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.subscriptions = exports.Subscriptions = void 0;
|
|
|
4
4
|
exports.useState = useState;
|
|
5
5
|
exports.useEffect = useEffect;
|
|
6
6
|
exports.useRender = useRender;
|
|
7
|
+
exports.useMemo = useMemo;
|
|
7
8
|
exports.useDispose = useDispose;
|
|
8
9
|
let currentReactor = [];
|
|
9
10
|
var reactor;
|
|
@@ -78,27 +79,70 @@ var subscriptions;
|
|
|
78
79
|
})(subscriptions || (exports.subscriptions = subscriptions = {}));
|
|
79
80
|
function useState(value) {
|
|
80
81
|
const reactors = new Set();
|
|
81
|
-
|
|
82
|
+
function getValue() {
|
|
82
83
|
const reactor = currentReactor[currentReactor.length - 1];
|
|
83
84
|
if (reactor) {
|
|
84
85
|
reactors.add(reactor);
|
|
85
86
|
reactor.states.set(reactors, reactor.iteration);
|
|
86
87
|
}
|
|
87
88
|
return value;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
}
|
|
90
|
+
;
|
|
91
|
+
function setValue(newValue) {
|
|
92
|
+
if (value !== newValue) {
|
|
93
|
+
value = newValue;
|
|
94
|
+
for (const reactor of reactors) {
|
|
95
|
+
renderReactor(reactor, reactor.effect);
|
|
96
|
+
}
|
|
93
97
|
}
|
|
94
|
-
}
|
|
95
|
-
|
|
98
|
+
}
|
|
99
|
+
;
|
|
100
|
+
return [getValue, setValue, cb => {
|
|
101
|
+
setValue(cb(value));
|
|
102
|
+
}];
|
|
96
103
|
}
|
|
97
104
|
function useEffect(cb, reaction = null) {
|
|
98
|
-
newSubscription(cb, reaction, true);
|
|
105
|
+
const sub = newSubscription(cb, reaction, true);
|
|
106
|
+
runSubscription(sub);
|
|
99
107
|
}
|
|
100
108
|
function useRender(cb, reaction = null) {
|
|
101
|
-
newSubscription(cb, reaction, false);
|
|
109
|
+
const sub = newSubscription(cb, reaction, false);
|
|
110
|
+
runSubscription(sub);
|
|
111
|
+
}
|
|
112
|
+
function useMemo(cb) {
|
|
113
|
+
const reactors = new Set();
|
|
114
|
+
let state = 0;
|
|
115
|
+
let value;
|
|
116
|
+
const sub = newSubscription(() => {
|
|
117
|
+
if (state === 0) {
|
|
118
|
+
sub.iteration--;
|
|
119
|
+
}
|
|
120
|
+
else if (state === 1) {
|
|
121
|
+
state = 2;
|
|
122
|
+
value = cb();
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
sub.iteration--;
|
|
126
|
+
state = 0;
|
|
127
|
+
for (const reactor of reactors) {
|
|
128
|
+
renderReactor(reactor, reactor.effect);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}, null, true);
|
|
132
|
+
return () => {
|
|
133
|
+
if (state === 0) {
|
|
134
|
+
state = 1;
|
|
135
|
+
runSubscription(sub);
|
|
136
|
+
}
|
|
137
|
+
if (!sub.cancelled) {
|
|
138
|
+
const reactor = currentReactor[currentReactor.length - 1];
|
|
139
|
+
if (reactor) {
|
|
140
|
+
reactors.add(reactor);
|
|
141
|
+
reactor.states.set(reactors, reactor.iteration);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return value;
|
|
145
|
+
};
|
|
102
146
|
}
|
|
103
147
|
function useDispose(cb) {
|
|
104
148
|
const container = currentSubscriptions[currentSubscriptions.length - 1];
|
|
@@ -107,8 +151,10 @@ function useDispose(cb) {
|
|
|
107
151
|
}
|
|
108
152
|
}
|
|
109
153
|
function newSubscription(cb, reaction, effect) {
|
|
110
|
-
|
|
154
|
+
return {
|
|
111
155
|
cb: cb,
|
|
156
|
+
firstRun: true,
|
|
157
|
+
lastValue: null,
|
|
112
158
|
reaction: reaction,
|
|
113
159
|
iteration: 0,
|
|
114
160
|
states: new Map(),
|
|
@@ -117,16 +163,6 @@ function newSubscription(cb, reaction, effect) {
|
|
|
117
163
|
cancelled: false,
|
|
118
164
|
pending: false
|
|
119
165
|
};
|
|
120
|
-
renderReactor(sub, true);
|
|
121
|
-
if (sub.states.size === 0) {
|
|
122
|
-
cancelSubscription(sub);
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
const container = currentSubscriptions[currentSubscriptions.length - 1];
|
|
126
|
-
if (container) {
|
|
127
|
-
container.list.push(sub);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
166
|
}
|
|
131
167
|
function cancelSubscription(sub) {
|
|
132
168
|
sub.cancelled = true;
|
|
@@ -136,6 +172,7 @@ function cancelSubscription(sub) {
|
|
|
136
172
|
}
|
|
137
173
|
function runSubscription(sub) {
|
|
138
174
|
sub.pending = false;
|
|
175
|
+
sub.iteration++;
|
|
139
176
|
reactor.set(sub);
|
|
140
177
|
const res = sub.cb();
|
|
141
178
|
reactor.reset();
|
|
@@ -144,5 +181,24 @@ function runSubscription(sub) {
|
|
|
144
181
|
sub.states.delete(state);
|
|
145
182
|
}
|
|
146
183
|
}
|
|
147
|
-
|
|
184
|
+
if (sub.states.size === 0) {
|
|
185
|
+
cancelSubscription(sub);
|
|
186
|
+
}
|
|
187
|
+
if (sub.firstRun) {
|
|
188
|
+
sub.firstRun = false;
|
|
189
|
+
if (sub.states.size > 0) {
|
|
190
|
+
const container = currentSubscriptions[currentSubscriptions.length - 1];
|
|
191
|
+
if (container) {
|
|
192
|
+
container.list.push(sub);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (sub.reaction) {
|
|
196
|
+
sub.lastValue = res;
|
|
197
|
+
sub.reaction(res, sub.cancelled);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else if (sub.reaction && sub.lastValue !== res) {
|
|
201
|
+
sub.lastValue = res;
|
|
202
|
+
sub.reaction(res, sub.cancelled);
|
|
203
|
+
}
|
|
148
204
|
}
|
package/lib/types/State.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
export type Getter<T> = () => T;
|
|
2
2
|
export type Setter<T> = (value: T) => void;
|
|
3
|
-
export type
|
|
4
|
-
export type
|
|
3
|
+
export type GetterSetter<T> = (cb: (value: T) => T) => void;
|
|
4
|
+
export type State<T> = [get: Getter<T>, set: Setter<T>, getSet: GetterSetter<T>];
|
|
5
|
+
type Subscription<T> = {
|
|
5
6
|
cb: () => T;
|
|
6
|
-
reaction: ((data: T, isState: boolean) => void) | null;
|
|
7
7
|
iteration: number;
|
|
8
|
+
lastValue: T | null;
|
|
9
|
+
firstRun: boolean;
|
|
10
|
+
reaction: ((data: T, lastReaction: boolean) => void) | null;
|
|
8
11
|
states: Map<Set<Subscription<any>>, number>;
|
|
9
12
|
next: Subscription<T> | null;
|
|
10
13
|
effect: boolean;
|
|
@@ -21,6 +24,8 @@ export declare namespace subscriptions {
|
|
|
21
24
|
function reset(): void;
|
|
22
25
|
}
|
|
23
26
|
export declare function useState<T>(value: T): State<T>;
|
|
24
|
-
export declare function useEffect<T>(cb: () => T, reaction?: ((data: T,
|
|
25
|
-
export declare function useRender<T>(cb: () => T, reaction?: ((data: T,
|
|
27
|
+
export declare function useEffect<T>(cb: () => T, reaction?: ((data: T, lastReaction: boolean) => void) | null): void;
|
|
28
|
+
export declare function useRender<T>(cb: () => T, reaction?: ((data: T, lastReaction: boolean) => void) | null): void;
|
|
29
|
+
export declare function useMemo<T>(cb: () => T): Getter<T>;
|
|
26
30
|
export declare function useDispose(cb: () => void): void;
|
|
31
|
+
export {};
|