bansa 0.0.6 → 0.0.8
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.ko.md +28 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.js +20 -0
- package/dist/react.d.ts +1 -1
- package/dist/react.js +14 -8
- package/package.json +20 -18
package/README.ko.md
CHANGED
|
@@ -226,7 +226,7 @@ userAtom.set({ id: 2, name: 'Alice' });
|
|
|
226
226
|
|
|
227
227
|
### 여러 상태 병합하기
|
|
228
228
|
|
|
229
|
-
`$$`로 여러 상태를 병합한 새로운 상태를 만들 수 있습니다.
|
|
229
|
+
`$$`로 여러 상태를 병합한 새로운 상태를 만들 수 있습니다. `$`와 사용법은 같지만, `$`의 `get` 함수는 `Promise`나 에러를 만났을 때 즉시 throw하는 반면, `$$`의 `get` 함수는 특별한 객체를 반환하여 최소한의 재실행으로 최대한의 의존성을 추적합니다. 또한, 배열이나 객체를 반환 시 한 단계 깊은 비교를 수행합니다.
|
|
230
230
|
|
|
231
231
|
다음 코드는 `$`로 상태를 병합하면 5초가 걸리는 반면에, `$$`로 상태를 병합하면 단 1초만이 걸립니다.
|
|
232
232
|
|
|
@@ -248,6 +248,33 @@ Object.setPrototypeOf(o, new Proxy(o, { get: (_, k) => k === Symbol.toPrimitive
|
|
|
248
248
|
|
|
249
249
|
이 코드의 `o`는 아무리 프로퍼티 접근 및 호출을 해도 같은 값을 반환합니다. 예를 들어, `o.a.b.c().d()().asdf()()()() === o`는 `true`입니다. 따라서, 셀렉터와 filter/map/reduce 등 간단한 메서드로 이뤄진 대부분의 상태 병합 함수에서 문제 없이 전체 코드를 실행할 수 있게 만듭니다. 하지만 만능은 아니므로 약간의 주의가 필요하며, 가급적 상태 병합에만 사용해야 합니다.
|
|
250
250
|
|
|
251
|
+
또한 상태 병합 시 특정 값들에서 부분씩만 가져와 새로운 객체를 만드는 경우가 흔하므로, `$$`로 병합한 상태의 의존성들이 너무 자주 재실행되지 않도록 `$`의 `equals`를 다음으로 설정합니다:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
const shallowEquals = (a: any, b: any): boolean => {
|
|
255
|
+
if (typeof a !== 'object' || typeof b !== 'object' || !a || !b) return false;
|
|
256
|
+
const c = a.constructor;
|
|
257
|
+
if (c !== b.constructor) return false;
|
|
258
|
+
|
|
259
|
+
if (c === Array) {
|
|
260
|
+
let i = a.length;
|
|
261
|
+
if (i !== b.length) return false;
|
|
262
|
+
while ((i = i - 1 | 0) >= 0) if (!Object.is(a[i], b[i])) return false;
|
|
263
|
+
return true;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
let n = 0;
|
|
267
|
+
for (const k in a) {
|
|
268
|
+
if (!(k in b && Object.is(a[k], b[k]))) return false;
|
|
269
|
+
n = n + 1 | 0;
|
|
270
|
+
}
|
|
271
|
+
for (const _ in b) if ((n = n - 1 | 0) < 0) return false;
|
|
272
|
+
return true;
|
|
273
|
+
};
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
정확히 한 단계만 더 비교하므로, `{ arr: [...] }`와 같은 객체의 경우 `arr`의 내용이 같더라도 참조가 다르다면 의존성이 재실행됩니다. 필요하다면 `arr` 부분은 다른 `$$`로 감싼 뒤 합치거나, 상태를 직접 `$`로 `equals`를 주고 만드세요.
|
|
277
|
+
|
|
251
278
|
## 상세
|
|
252
279
|
|
|
253
280
|
### 상태를 얼마나 쪼개는 게 좋나요?
|
package/dist/index.browser.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var s=function(){};s.prototype.get=function(){if(this.
|
|
1
|
+
var s=function(){};s.prototype.get=function(){if(this.r||(v(this),l(this)),this.state.promise)throw this.state.promise;if(this.state.error)throw this.state.error;return this.state.value};s.prototype.watch=function(e){return this.r||w(this),(this.l??=new Set).add(e),()=>{this.l.delete(e),this.l.size||l(this)}};s.prototype.subscribe=function(e){let t={d:e,V:{get signal(){return(t.t??=g()).signal}}};if(!this.r)w(this);else if(!this.state.promise&&!this.state.error)try{e(this.state.value,t.V)}catch(r){A(r)}return(this.s??=new Set).add(t),()=>{this.s.delete(t),t.t&&(t.t.abort(),t.t=void 0),this.s.size||l(this)}};s.prototype[Symbol.toPrimitive]=function(){return this.state.value};var u=function(e,t){this.c=t?.equals,this.state={promise:void 0,error:void 0,value:e},this.state.value=this.a=e};u.prototype.set=function(e){let t=e instanceof Function?e(this.a):e;h(t,this.state.value,this.c)||(this.a=t,f(this))};u.prototype.A=!0;u.prototype.r=!0;u.prototype.n=!1;Object.setPrototypeOf(u.prototype,s.prototype);var p=function(e,t){this.y=e,this.c=t?.equals,this.h=t?.persist,this.state={promise:S,error:void 0,value:void 0};let r=this;this.V={get signal(){return(r.t??=g()).signal}}};p.prototype.A=!1;p.prototype.r=!1;p.prototype.n=!1;p.prototype.i=0;Object.setPrototypeOf(p.prototype,s.prototype);var c=()=>c,k=()=>{};Object.setPrototypeOf(c,new Proxy(c,{get:(e,t)=>t===Symbol.toPrimitive?k:c}));var S=Promise.resolve(),_=(e,t)=>e instanceof Function?new p(e,t):new u(e,t),D=e=>_((t,r)=>{let o,n,m=e(x=>{try{return t(x)}catch(V){if(!V)throw V;b(V)?(o??=[]).push(V):n=V}return c},r);if(n)throw n;if(o)throw Promise.all(o);return m},{equals:O}),O=(e,t)=>{if(typeof e!="object"||typeof t!="object"||!e||!t)return!1;let r=e.constructor;if(r!==t.constructor)return!1;if(r===Array){let n=e.length;if(n!==t.length)return!1;for(;(n=n-1|0)>=0;)if(!Object.is(e[n],t[n]))return!1;return!0}let o=0;for(let n in e){if(!(n in t&&Object.is(e[n],t[n])))return!1;o=o+1|0}for(let n in t)if((o=o-1|0)<0)return!1;return!0},y=!1,a=[],w=e=>{e.u||(e.u=!0,f(e))},f=e=>{e.n||(e.n=!0,a.push(e),y||(y=!0,queueMicrotask(G)))},G=()=>{y=!1;{let t=a;a=[];for(let r of t)r.state.promise=void 0,r.state.error=r.f,r.state.value=r.a,P(r)}let e=a;a=[];for(let t=e.length;t--;){let r=e[t];r.m=!1,r.u&&(r.n=!0,v(r)),r.n&&I(r)}},I=e=>{if(e.n=!1,e.o)for(let t of e.o)t.u=!0;if(e.l)for(let t of e.l)t();if(e.s&&!e.state.promise&&!e.state.error)for(let t of e.s){t.t&&(t.t.abort(),t.t=void 0);try{t.d(e.state.value,t.V)}catch(r){A(r)}}},P=e=>{if(!e.m){if(e.m=!0,e.o)for(let t of e.o)P(t);a.push(e)}},i=class{e;constructor(t){this.e=t}},v=e=>{let t=++e.i;e.r=!0,e.u=!1,e.state.promise=void 0,e.t&&(e.t.abort(),e.t=void 0);let r=e.p;r&&(e.p=new Set);try{let o=e.y((n,m=!0)=>{if(t!==e.i)throw void 0;if(e!==n&&(n.r||(v(n),n.n&&(n.n=!1,I(n))),r?.delete(n),(e.p??=new Set).add(n),(n.o??=new Set).add(e)),!m)return n.state;if(n.state.promise)throw new i(n.state.promise);if(n.state.error)throw new i(n.state.error);return n.state.value},e.V);b(o)?(e.state.promise=o,o.then(n=>{t===e.i&&(h(n,e.state.value,e.c)?e.state.promise=void 0:(e.a=n,e.f=void 0,f(e)))},n=>{t===e.i&&(n instanceof Promise?e.state.promise=void 0:(n instanceof i?n=n.e:A(n),e.f=n,f(e)))})):(++e.i,e.state.error=void 0,h(o,e.state.value,e.c)?e.n=!1:e.state.value=e.a=o)}catch(o){++e.i,o?(o instanceof i?o=o.e:A(o),b(o)?e.state.promise=o:e.state.error=o):e.n=!1}if(r)for(let o of r)o.o.delete(e),l(o)},d=!1,l=e=>{if(!e.A&&!e.h&&!e.o?.size&&!e.l?.size&&!e.s?.size){if(!d){setTimeout(()=>{d=!0,l(e),d=!1},0);return}if(e.state.promise=S,e.a=e.f=e.state.error=e.state.value=void 0,e.n=e.u=e.r=!1,e.t&&(e.t.abort(),e.t=void 0),e.p){for(let t of e.p)t.o.delete(e),l(t);e.p.clear()}}},h=(e,t,r)=>Object.is(e,t)||r!==void 0&&t!==void 0&&r(e,t),b=e=>typeof e?.then=="function",g=()=>{let e=new AbortController,t=e.signal,r=new Promise(o=>{t.then=n=>r.then(n),t.addEventListener("abort",o,{once:!0,passive:!0})});return{abort:()=>e.abort(),signal:t}},A=e=>{queueMicrotask(()=>{throw e})};export{_ as $,D as $$,S as inactive};
|
package/dist/index.js
CHANGED
|
@@ -133,7 +133,27 @@ const $$ = (init) => $((get, options) => {
|
|
|
133
133
|
if (error) throw error;
|
|
134
134
|
if (promises) throw Promise.all(promises);
|
|
135
135
|
return result;
|
|
136
|
+
}, {
|
|
137
|
+
equals: shallowEquals
|
|
136
138
|
});
|
|
139
|
+
const shallowEquals = (a, b) => {
|
|
140
|
+
if (typeof a !== "object" || typeof b !== "object" || !a || !b) return false;
|
|
141
|
+
const c = a.constructor;
|
|
142
|
+
if (c !== b.constructor) return false;
|
|
143
|
+
if (c === Array) {
|
|
144
|
+
let i = a.length;
|
|
145
|
+
if (i !== b.length) return false;
|
|
146
|
+
while ((i = i - 1 | 0) >= 0) if (!Object.is(a[i], b[i])) return false;
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
let n = 0;
|
|
150
|
+
for (const k in a) {
|
|
151
|
+
if (!(k in b && Object.is(a[k], b[k]))) return false;
|
|
152
|
+
n = n + 1 | 0;
|
|
153
|
+
}
|
|
154
|
+
for (const _ in b) if ((n = n - 1 | 0) < 0) return false;
|
|
155
|
+
return true;
|
|
156
|
+
};
|
|
137
157
|
let pendingUpdateAtoms = false;
|
|
138
158
|
let stack = [];
|
|
139
159
|
const requestActivate = (atom) => {
|
package/dist/react.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Atom, DerivedAtom, PrimitiveAtom } from '.';
|
|
2
|
-
export declare const useAtom: <Value>(atom: PrimitiveAtom<Value>) => readonly [Value, (value: import(".").AtomUpdater<Value>) => void];
|
|
3
2
|
export declare const useAtomValue: <Value>(atom: Atom<Value>) => Value;
|
|
4
3
|
export declare const useAtomState: <Value>(atom: DerivedAtom<Value>) => import(".").AtomState<Value>;
|
|
4
|
+
export declare const useAtom: <Value>(atom: PrimitiveAtom<Value>) => readonly [Value, (newState: Value) => void];
|
|
5
5
|
export declare const useStateAtom: <Value>(atom: PrimitiveAtom<Value>) => readonly [Value, (newState: Value) => void];
|
package/dist/react.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { useState, useSyncExternalStore } from "react";
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
const useAtomValue = (atom) => useSyncExternalStore(
|
|
3
|
+
(watcher) => atom.watch(watcher),
|
|
4
|
+
() => atom.get()
|
|
5
|
+
);
|
|
6
|
+
const useAtomState = (atom) => useSyncExternalStore(
|
|
7
|
+
(watcher) => atom.watch(watcher),
|
|
8
|
+
() => {
|
|
9
|
+
try {
|
|
10
|
+
atom.get();
|
|
11
|
+
} catch (_) {
|
|
12
|
+
}
|
|
13
|
+
return atom.state;
|
|
8
14
|
}
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
);
|
|
16
|
+
const useAtom = (atom) => [useAtomValue(atom), (newState) => atom.set(newState)];
|
|
11
17
|
const useStateAtom = (atom) => {
|
|
12
18
|
const [state, setState] = useState(() => atom.get());
|
|
13
19
|
const setStateWithAtom = (newState) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bansa",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -16,13 +16,23 @@
|
|
|
16
16
|
"default": "./dist/index.js"
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "pnpm run \"/^build:.*/\"",
|
|
21
|
+
"build:types": "tsc --noEmit false --emitDeclarationOnly --outDir dist",
|
|
22
|
+
"build:index": "esbuild src/index.ts --mangle-props=^_ --format=esm --target=es2022 --outfile=dist/index.js",
|
|
23
|
+
"build:index-browser": "esbuild src/index.ts --mangle-props=^_ --minify --bundle --format=esm --target=es2022 --platform=browser --outfile=dist/index.browser.js",
|
|
24
|
+
"build:react": "esbuild src/react.tsx --mangle-props=^_ --format=esm --target=es2022 --outfile=dist/react.js",
|
|
25
|
+
"test": "vitest",
|
|
26
|
+
"format": "biome format --write ./src",
|
|
27
|
+
"prepare": "pnpm run build"
|
|
28
|
+
},
|
|
19
29
|
"devDependencies": {
|
|
20
|
-
"@biomejs/biome": "2.
|
|
21
|
-
"@types/react": "^19.1.
|
|
22
|
-
"@types/react-dom": "^19.1.
|
|
23
|
-
"esbuild": "^0.25.
|
|
24
|
-
"typescript": "^5.
|
|
25
|
-
"vitest": "^3.
|
|
30
|
+
"@biomejs/biome": "^2.2.4",
|
|
31
|
+
"@types/react": "^19.1.15",
|
|
32
|
+
"@types/react-dom": "^19.1.9",
|
|
33
|
+
"esbuild": "^0.25.10",
|
|
34
|
+
"typescript": "^5.9.2",
|
|
35
|
+
"vitest": "^3.2.4"
|
|
26
36
|
},
|
|
27
37
|
"peerDependencies": {
|
|
28
38
|
"@types/react": ">=17.0.0",
|
|
@@ -45,19 +55,11 @@
|
|
|
45
55
|
"publishConfig": {
|
|
46
56
|
"access": "public"
|
|
47
57
|
},
|
|
58
|
+
"packageManager": "pnpm@10.17.1",
|
|
48
59
|
"homepage": "https://github.com/cgiosy/bansa",
|
|
49
60
|
"keywords": [
|
|
50
61
|
"bansa",
|
|
51
62
|
"state",
|
|
52
63
|
"react"
|
|
53
|
-
]
|
|
54
|
-
|
|
55
|
-
"build": "pnpm run \"/^build:.*/\"",
|
|
56
|
-
"build:types": "tsc --noEmit false --emitDeclarationOnly --outDir dist",
|
|
57
|
-
"build:index": "esbuild src/index.ts --mangle-props=^_ --format=esm --target=es2022 --outfile=dist/index.js",
|
|
58
|
-
"build:index-browser": "esbuild src/index.ts --mangle-props=^_ --minify --bundle --format=esm --target=es2022 --platform=browser --outfile=dist/index.browser.js",
|
|
59
|
-
"build:react": "esbuild src/react.tsx --mangle-props=^_ --format=esm --target=es2022 --outfile=dist/react.js",
|
|
60
|
-
"test": "vitest",
|
|
61
|
-
"format": "biome format --write ./src"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
+
]
|
|
65
|
+
}
|