react-use-singleton-hook 1.0.14 → 1.0.16

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.
Files changed (3) hide show
  1. package/README.md +50 -0
  2. package/dist/main.js +40 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -24,6 +24,56 @@ pnpm add react-use-singleton-hook
24
24
 
25
25
  This assumes that you’re using [npm](http://npmjs.com/) package manager
26
26
 
27
+ ## What is a singleton hook
28
+
29
+ - **Works like React Context**: A singleton hook encapsulates shared state logic and exposes it to any component that calls the hook, similar to how context provides values to consumers.
30
+ - **Mounts lazily**: The hook logic runs only when the first component uses it. After mounting, it stays active for the app’s lifetime unless configured to unmount.
31
+ - **No setup required**: No need for context providers or changes to your app structure. The hook uses React’s built-in hooks and a hidden DOM node for efficient, portable state management.
32
+
33
+ ## Examples
34
+
35
+ #### dark/light mode switch
36
+ Whenever `Configurator` changes darkMode, all subscribed components are updated.
37
+
38
+ ```javascript
39
+ /*************** file:src/services/darkMode.js ***************/
40
+ import { useState } from 'react';
41
+ import { createSingletonGlobalState } from 'react-use-singleton-hook';
42
+
43
+ const initDarkMode = false;
44
+ let globalSetMode = () => { throw new Error('you must useDarkMode before setting its state'); };
45
+
46
+ export const useDarkMode = createSingletonGlobalState(initDarkMode, () => {
47
+ const [mode, setMode] = useState(initDarkMode);
48
+ globalSetMode = setMode;
49
+ return mode;
50
+ });
51
+
52
+ export const setDarkMode = mode => globalSetMode(mode);
53
+
54
+
55
+ /*************** file:src/compoents/App.js ***************/
56
+
57
+ import React from 'react';
58
+ import { useDarkMode, setDarkMode } from 'src/services/darkMode';
59
+
60
+ const Consumer1 = () => {
61
+ const mode = useDarkMode();
62
+ return <div className={`is-dark-${mode}`}>Consumer1 - {`${mode}`}</div>;
63
+ };
64
+
65
+ const Consumer2 = () => {
66
+ const mode = useDarkMode();
67
+ return <div className={`is-dark-${mode}`}>Consumer2 - {`${mode}`}</div>;
68
+ };
69
+
70
+ const Configurator = () => {
71
+ const mode = useDarkMode();
72
+ return <button onClick={() => setDarkMode(!mode)}>Toggle dark/light</button>;
73
+ };
74
+
75
+ ```
76
+
27
77
  ### Compatibility
28
78
 
29
79
  - ✅ Supports React 18.x and 19.x
package/dist/main.js CHANGED
@@ -1,49 +1,59 @@
1
1
  import i, { useEffect as v } from "react";
2
- import { createRoot as E } from "react-dom/client";
3
- const g = (t) => {
4
- let e;
5
- const u = /* @__PURE__ */ new Set(), l = (o, s) => {
6
- const n = typeof o == "function" ? o(e) : o;
7
- if (!Object.is(n, e)) {
8
- const m = e;
9
- e = s ?? (typeof n != "object" || n === null) ? n : Object.assign({}, e, n), u.forEach((b) => b(e, m));
2
+ import { createRoot as h } from "react-dom/client";
3
+ const g = (e) => {
4
+ let n;
5
+ const s = /* @__PURE__ */ new Set(), l = (u, o) => {
6
+ const t = typeof u == "function" ? u(n) : u;
7
+ if (!Object.is(t, n)) {
8
+ const m = n;
9
+ n = o ?? (typeof t != "object" || t === null) ? t : Object.assign({}, n, t), s.forEach((b) => b(n, m));
10
10
  }
11
- }, a = () => e, c = { setState: l, getState: a, getInitialState: () => r, subscribe: (o) => (u.add(o), () => u.delete(o)) }, r = e = t(l, a, c);
11
+ }, a = () => n, c = { setState: l, getState: a, getInitialState: () => r, subscribe: (u) => (s.add(u), () => s.delete(u)) }, r = n = e(l, a, c);
12
12
  return c;
13
- }, h = ((t) => t ? g(t) : g), k = (t) => t;
14
- function C(t, e = k) {
15
- const u = i.useSyncExternalStore(
16
- t.subscribe,
17
- i.useCallback(() => e(t.getState()), [t, e]),
18
- i.useCallback(() => e(t.getInitialState()), [t, e])
13
+ }, k = ((e) => e ? g(e) : g), E = (e) => e;
14
+ function C(e, n = E) {
15
+ const s = i.useSyncExternalStore(
16
+ e.subscribe,
17
+ i.useCallback(() => n(e.getState()), [e, n]),
18
+ i.useCallback(() => n(e.getInitialState()), [e, n])
19
19
  );
20
- return i.useDebugValue(u), u;
20
+ return i.useDebugValue(s), s;
21
21
  }
22
- const j = (t, e, u = {}) => {
23
- const { mountId: l, unmountIfNoConsumers: a = !0 } = u, f = typeof t == "function";
24
- let S = !f, c = f ? void 0 : t;
25
- const r = h(() => ({ value: c }));
26
- let o = 0, s = null, n = null;
22
+ const j = (e, n, s = {}) => {
23
+ const { mountId: l, unmountIfNoConsumers: a = !0 } = s, f = typeof e == "function";
24
+ let S = !f, c = f ? void 0 : e;
25
+ const r = k(() => ({ value: c }));
26
+ let u = 0, o = null, t = null;
27
27
  function m() {
28
- const d = e();
28
+ const d = n();
29
29
  return v(() => {
30
30
  r.setState({ value: d });
31
31
  }, [d]), null;
32
32
  }
33
33
  function b() {
34
- s || (n = document.createElement("div"), n.style.display = "none", l && (n.id = l), document.body.appendChild(n), s = E(n), s.render(i.createElement(m)));
35
- }
36
- function I() {
37
- !s || !n || (s.unmount(), n.remove(), s = null, n = null);
34
+ if (o) {
35
+ if (t && document.body.contains(t)) return;
36
+ try {
37
+ o.unmount();
38
+ } catch {
39
+ }
40
+ o = null, t = null;
41
+ }
42
+ t = document.createElement("div"), t.style.display = "none", l && (t.id = l), document.body.appendChild(t), o = h(t), o.render(i.createElement(m));
38
43
  }
39
44
  function y() {
40
- !S && f && (S = !0, c = t(), r.setState({ value: c }));
45
+ !o || !t || queueMicrotask(() => {
46
+ !o || !t || u > 0 || (o.unmount(), t.remove(), o = null, t = null);
47
+ });
48
+ }
49
+ function I() {
50
+ !S && f && (S = !0, c = e(), r.setState({ value: c }));
41
51
  }
42
52
  function R() {
43
- y();
53
+ I();
44
54
  const d = C(r, (p) => p.value);
45
- return v(() => (o += 1, o === 1 && b(), () => {
46
- o -= 1, o === 0 && a && I();
55
+ return v(() => (u += 1, o || b(), () => {
56
+ u -= 1, u === 0 && a && y();
47
57
  }), []), d;
48
58
  }
49
59
  return R;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-use-singleton-hook",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "type": "module",
5
5
  "main": "dist/main.js",
6
6
  "module": "dist/main.js",