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 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]
@@ -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, isState) => {
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 (isState) {
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
- const getValue = () => {
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
- const setValue = (newValue) => {
90
- value = newValue;
91
- for (const reactor of reactors) {
92
- renderReactor(reactor, reactor.effect);
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
- return [getValue, setValue];
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
- const sub = {
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
- sub.reaction?.(res, sub.states.size > 0);
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
  }
@@ -1,10 +1,13 @@
1
1
  export type Getter<T> = () => T;
2
2
  export type Setter<T> = (value: T) => void;
3
- export type State<T> = [get: Getter<T>, set: Setter<T>];
4
- export type Subscription<T> = {
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, isState: boolean) => void) | null): void;
25
- export declare function useRender<T>(cb: () => T, reaction?: ((data: T, isState: boolean) => void) | null): void;
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 {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nesquick",
3
- "version": "0.0.27",
3
+ "version": "1.1.0",
4
4
  "description": "React-like library with focus on drawing performance",
5
5
  "types": "./lib/types",
6
6
  "main": "./lib",