react-usectx 1.0.7 → 1.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.md +61 -0
- package/context.js +48 -0
- package/create-context.js +23 -0
- package/index.js +2 -3
- package/package.json +2 -2
- package/src/context.ts +52 -23
- package/src/index.ts +2 -0
- package/index.ts +0 -3
- package/intex.ts +0 -3
- package/src/context.js +0 -25
- package/src/create-context.js +0 -38
package/README.md
CHANGED
|
@@ -45,6 +45,32 @@ const setMyContext = updateCtx("stateName");
|
|
|
45
45
|
setMyContext({ name: "Rick Ross" });
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
### useReducer
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
import { useReducer } from "react-usectx";
|
|
52
|
+
|
|
53
|
+
const fullName = useReducer("stateName", (data) => {
|
|
54
|
+
return `${data.firstName} ${data.lastName}`;
|
|
55
|
+
});
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Params
|
|
59
|
+
|
|
60
|
+
### stateName
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
const myContextID = "MyUniqueIdentifier";
|
|
64
|
+
|
|
65
|
+
useCtx(myContextID);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The stateName serves as a unique identifier for a shared state object. Internally, the state manager maintains a list of state entries, each associated with a distinct stateName.
|
|
69
|
+
|
|
70
|
+
When any of the provided functions—useCtx, updateCtx, or getCtx—are invoked, the state manager checks whether a state object with the specified stateName already exists. If it does not, a new state entry is automatically created and initialized.
|
|
71
|
+
|
|
72
|
+
This mechanism enables global state sharing across components. For example, calling getCtx("example-1") in one component will return the same state reference when called with "example-1" in any other component within the same document. This allows for seamless state synchronization across different parts of your application without the need for explicit context providers.
|
|
73
|
+
|
|
48
74
|
## Example
|
|
49
75
|
|
|
50
76
|
```js
|
|
@@ -77,3 +103,38 @@ function Title() {
|
|
|
77
103
|
);
|
|
78
104
|
}
|
|
79
105
|
```
|
|
106
|
+
|
|
107
|
+
## Example with reducer
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
function Page() {
|
|
111
|
+
const [title, setTitle] = useCtx("title");
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<div className="wrapper">
|
|
115
|
+
<form>
|
|
116
|
+
<label htmlFor="text">Enter text</label>
|
|
117
|
+
<input
|
|
118
|
+
type="text"
|
|
119
|
+
id="text"
|
|
120
|
+
onChange={(e) => setTitle(e.target.value)}
|
|
121
|
+
/>
|
|
122
|
+
</form>
|
|
123
|
+
<Title></Title>
|
|
124
|
+
<p>{title}</p>
|
|
125
|
+
</div>
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function Title() {
|
|
130
|
+
const reducedTitle: string = useReducer(
|
|
131
|
+
"title",
|
|
132
|
+
(title) => `Title is: ${title.toUpperCase()}`
|
|
133
|
+
);
|
|
134
|
+
return (
|
|
135
|
+
<h1>
|
|
136
|
+
<strong>{reducedTitle}</strong>
|
|
137
|
+
</h1>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
```
|
package/context.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { CreateContext } from "./create-context";
|
|
4
|
+
const cache = {};
|
|
5
|
+
const getInstance = (name) => {
|
|
6
|
+
if (!cache[name]) {
|
|
7
|
+
cache[name] = new CreateContext();
|
|
8
|
+
}
|
|
9
|
+
return cache[name];
|
|
10
|
+
};
|
|
11
|
+
export function updateCtx(name) {
|
|
12
|
+
const ctx = getInstance(name);
|
|
13
|
+
return ctx.commit.bind(ctx);
|
|
14
|
+
}
|
|
15
|
+
export function getCtx(name) {
|
|
16
|
+
const context = getInstance(name);
|
|
17
|
+
const subscription = (callback) => {
|
|
18
|
+
context.subscribe(callback);
|
|
19
|
+
return () => context.unsubscribe(callback);
|
|
20
|
+
};
|
|
21
|
+
return useSyncExternalStore(subscription, context.getState.bind(context), context.getState.bind(context));
|
|
22
|
+
}
|
|
23
|
+
export function useCtx(name) {
|
|
24
|
+
return [getCtx(name), updateCtx(name)];
|
|
25
|
+
}
|
|
26
|
+
const reducerCache = {};
|
|
27
|
+
export function useReducer(name, modiFier, useCache = true) {
|
|
28
|
+
if (!reducerCache[name]) {
|
|
29
|
+
reducerCache[name] = new WeakMap();
|
|
30
|
+
}
|
|
31
|
+
const context = getInstance(name);
|
|
32
|
+
const _getState = context.getState.bind(context);
|
|
33
|
+
const getState = () => {
|
|
34
|
+
const state = _getState();
|
|
35
|
+
const cache = reducerCache[name].get(state);
|
|
36
|
+
if (cache && useCache) {
|
|
37
|
+
return cache;
|
|
38
|
+
}
|
|
39
|
+
const res = modiFier(state);
|
|
40
|
+
reducerCache[name].set(state, res);
|
|
41
|
+
return res;
|
|
42
|
+
};
|
|
43
|
+
const subscription = (callback) => {
|
|
44
|
+
context.subscribe(callback);
|
|
45
|
+
return () => context.unsubscribe(callback);
|
|
46
|
+
};
|
|
47
|
+
return useSyncExternalStore(subscription, getState, getState);
|
|
48
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class CreateContext {
|
|
2
|
+
#eventHandlers = [];
|
|
3
|
+
#state = null;
|
|
4
|
+
subscribe(handler) {
|
|
5
|
+
this.#eventHandlers.push(handler);
|
|
6
|
+
}
|
|
7
|
+
unsubscribe(handler) {
|
|
8
|
+
const index = this.#eventHandlers.indexOf(handler);
|
|
9
|
+
if (index !== -1) {
|
|
10
|
+
this.#eventHandlers.splice(index, 1);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
commit(state) {
|
|
14
|
+
this.setState(state);
|
|
15
|
+
this.#eventHandlers.forEach((callback) => callback.call(undefined, state));
|
|
16
|
+
}
|
|
17
|
+
setState(state) {
|
|
18
|
+
this.#state = state;
|
|
19
|
+
}
|
|
20
|
+
getState() {
|
|
21
|
+
return this.#state;
|
|
22
|
+
}
|
|
23
|
+
}
|
package/index.js
CHANGED
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
export { useCtx as default } from "./
|
|
2
|
-
export { getCtx } from "./
|
|
3
|
-
export { updateCtx } from "./src/context";
|
|
1
|
+
export { useCtx as default } from "./context";
|
|
2
|
+
export { getCtx, useReducer, updateCtx } from "./context";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-usectx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
19
|
"test": "jest",
|
|
20
|
-
"build": "npx tsc index.ts --target
|
|
20
|
+
"build": "npx tsc ./src/index.ts --target es2022 --outDir ./"
|
|
21
21
|
},
|
|
22
22
|
"author": "",
|
|
23
23
|
"homepage": "https://jsf7.dev/react-usectx",
|
package/src/context.ts
CHANGED
|
@@ -1,37 +1,66 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
2
|
|
|
3
|
-
import { ReactNode, useSyncExternalStore } from
|
|
4
|
-
import { CreateContext } from
|
|
3
|
+
import { ReactNode, useSyncExternalStore } from "react";
|
|
4
|
+
import { CreateContext } from "./create-context";
|
|
5
5
|
|
|
6
|
-
type cache = { [key: string]: InstanceType<typeof CreateContext> }
|
|
6
|
+
type cache = { [key: string]: InstanceType<typeof CreateContext> };
|
|
7
7
|
|
|
8
|
-
const cache: cache = {}
|
|
8
|
+
const cache: cache = {};
|
|
9
9
|
|
|
10
10
|
const getInstance = (name: string): InstanceType<typeof CreateContext> => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
11
|
+
if (!cache[name]) {
|
|
12
|
+
cache[name] = new CreateContext();
|
|
13
|
+
}
|
|
14
|
+
return cache[name];
|
|
15
|
+
};
|
|
16
16
|
|
|
17
17
|
export function updateCtx(name: string): Function {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
const ctx = getInstance(name);
|
|
19
|
+
return ctx.commit.bind(ctx);
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function getCtx<Snapshot>(name: string): Snapshot {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
const context = getInstance(name);
|
|
24
|
+
const subscription = (callback: Function) => {
|
|
25
|
+
context.subscribe(callback);
|
|
26
|
+
return () => context.unsubscribe(callback);
|
|
27
|
+
};
|
|
28
|
+
return useSyncExternalStore(
|
|
29
|
+
subscription,
|
|
30
|
+
context.getState.bind(context),
|
|
31
|
+
context.getState.bind(context)
|
|
32
|
+
);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export function useCtx(name: string): [ReactNode, Function] {
|
|
36
|
-
|
|
36
|
+
return [getCtx(name), updateCtx(name)];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const reducerCache: { [key: string]: WeakMap<any, any> } = {};
|
|
40
|
+
|
|
41
|
+
export function useReducer<Snapshot>(
|
|
42
|
+
name: string,
|
|
43
|
+
modiFier: (data: any) => Snapshot,
|
|
44
|
+
useCache: boolean = true
|
|
45
|
+
): Snapshot {
|
|
46
|
+
if (!reducerCache[name]) {
|
|
47
|
+
reducerCache[name] = new WeakMap();
|
|
48
|
+
}
|
|
49
|
+
const context = getInstance(name);
|
|
50
|
+
const _getState = context.getState.bind(context);
|
|
51
|
+
const getState = () => {
|
|
52
|
+
const state = _getState();
|
|
53
|
+
const cache = reducerCache[name].get(state);
|
|
54
|
+
if (cache && useCache) {
|
|
55
|
+
return cache;
|
|
56
|
+
}
|
|
57
|
+
const res = modiFier(state);
|
|
58
|
+
reducerCache[name].set(state, res);
|
|
59
|
+
return res;
|
|
60
|
+
};
|
|
61
|
+
const subscription = (callback: Function) => {
|
|
62
|
+
context.subscribe(callback);
|
|
63
|
+
return () => context.unsubscribe(callback);
|
|
64
|
+
};
|
|
65
|
+
return useSyncExternalStore(subscription, getState, getState);
|
|
37
66
|
}
|
package/src/index.ts
ADDED
package/index.ts
DELETED
package/intex.ts
DELETED
package/src/context.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { useSyncExternalStore } from 'react';
|
|
3
|
-
import { CreateContext } from './create-context';
|
|
4
|
-
const cache = {};
|
|
5
|
-
const getInstance = (name) => {
|
|
6
|
-
if (!cache[name]) {
|
|
7
|
-
cache[name] = new CreateContext();
|
|
8
|
-
}
|
|
9
|
-
return cache[name];
|
|
10
|
-
};
|
|
11
|
-
export function updateCtx(name) {
|
|
12
|
-
const ctx = getInstance(name);
|
|
13
|
-
return ctx.commit.bind(ctx);
|
|
14
|
-
}
|
|
15
|
-
export function getCtx(name) {
|
|
16
|
-
const context = getInstance(name);
|
|
17
|
-
const subscription = (callback) => {
|
|
18
|
-
context.subscribe(callback);
|
|
19
|
-
return () => context.unsubscribe(callback);
|
|
20
|
-
};
|
|
21
|
-
return useSyncExternalStore(subscription, context.getState.bind(context), context.getState.bind(context));
|
|
22
|
-
}
|
|
23
|
-
export function useCtx(name) {
|
|
24
|
-
return [getCtx(name), updateCtx(name)];
|
|
25
|
-
}
|
package/src/create-context.js
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
2
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
3
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
4
|
-
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
5
|
-
};
|
|
6
|
-
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
7
|
-
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
8
|
-
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
9
|
-
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
10
|
-
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
11
|
-
};
|
|
12
|
-
var _CreateContext_eventHandlers, _CreateContext_state;
|
|
13
|
-
export class CreateContext {
|
|
14
|
-
constructor() {
|
|
15
|
-
_CreateContext_eventHandlers.set(this, []);
|
|
16
|
-
_CreateContext_state.set(this, null);
|
|
17
|
-
}
|
|
18
|
-
subscribe(handler) {
|
|
19
|
-
__classPrivateFieldGet(this, _CreateContext_eventHandlers, "f").push(handler);
|
|
20
|
-
}
|
|
21
|
-
unsubscribe(handler) {
|
|
22
|
-
const index = __classPrivateFieldGet(this, _CreateContext_eventHandlers, "f").indexOf(handler);
|
|
23
|
-
if (index !== -1) {
|
|
24
|
-
__classPrivateFieldGet(this, _CreateContext_eventHandlers, "f").splice(index, 1);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
commit(state) {
|
|
28
|
-
this.setState(state);
|
|
29
|
-
__classPrivateFieldGet(this, _CreateContext_eventHandlers, "f").forEach((callback) => callback.call(undefined, state));
|
|
30
|
-
}
|
|
31
|
-
setState(state) {
|
|
32
|
-
__classPrivateFieldSet(this, _CreateContext_state, state, "f");
|
|
33
|
-
}
|
|
34
|
-
getState() {
|
|
35
|
-
return __classPrivateFieldGet(this, _CreateContext_state, "f");
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
_CreateContext_eventHandlers = new WeakMap(), _CreateContext_state = new WeakMap();
|