wenay-react2 1.0.4 → 1.0.5

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.
@@ -1,5 +1,9 @@
1
- type tFunc2 = Map<object, (a?: any) => void>;
2
- export declare const map3: WeakMap<object, tFunc2>;
1
+ type Listener = (a?: any) => void;
2
+ interface ObserverState {
3
+ listeners: Set<Listener>;
4
+ version: number;
5
+ }
6
+ export declare const map3: WeakMap<object, ObserverState>;
3
7
  export declare const mapWait: Map<object, {
4
8
  refreshAsync: (ms: number, func: () => any) => void;
5
9
  refreshAsync2: (ms: number, func: () => any) => Promise<void>;
@@ -1,88 +1,189 @@
1
- import { useLayoutEffect, useState } from "react";
1
+ import { useLayoutEffect, useSyncExternalStore } from "react";
2
2
  import { waitRun } from "wenay-common2";
3
3
  export const map3 = new WeakMap();
4
4
  export const mapWait = new Map();
5
+ function getObserverState(obj) {
6
+ let state = map3.get(obj);
7
+ if (!state) {
8
+ state = { listeners: new Set(), version: 0 };
9
+ map3.set(obj, state);
10
+ }
11
+ return state;
12
+ }
13
+ function triggerUpdate(obj, reverse = false, lastOnly = false) {
14
+ const state = map3.get(obj);
15
+ if (!state || state.listeners.size === 0)
16
+ return;
17
+ state.version += 1;
18
+ let listenersArray = Array.from(state.listeners);
19
+ if (lastOnly) {
20
+ const last = listenersArray.at(-1);
21
+ if (last)
22
+ last(obj);
23
+ return;
24
+ }
25
+ if (reverse) {
26
+ listenersArray.reverse();
27
+ }
28
+ listenersArray.forEach(listener => listener(obj));
29
+ }
5
30
  export function renderBy(a, ms) {
6
- const t = () => map3.get(a)?.forEach(e => e(a));
7
31
  if (ms) {
8
32
  (mapWait.get(a) || mapWait.set(a, waitRun()).get(a))
9
33
  .refreshAsync(ms, () => {
10
34
  mapWait.delete(a);
11
- t();
35
+ triggerUpdate(a);
12
36
  });
13
37
  }
14
38
  else
15
- t();
39
+ triggerUpdate(a);
16
40
  }
17
41
  export function renderByRevers(a, ms, reverse = true) {
18
- const ar = [];
19
- map3.get(a)?.forEach(e => ar.push(e));
20
- const t = reverse ? () => ar.reverse().forEach(e => e(a))
21
- : () => ar.forEach(e => e(a));
22
42
  if (ms) {
23
43
  (mapWait.get(a) || mapWait.set(a, waitRun()).get(a))
24
44
  .refreshAsync(ms, () => {
25
45
  mapWait.delete(a);
26
- t();
46
+ triggerUpdate(a, reverse);
27
47
  });
28
48
  }
29
49
  else
30
- t();
50
+ triggerUpdate(a, reverse);
31
51
  }
32
52
  export function renderByLast(a, ms) {
33
- const ar = [];
34
- map3.get(a)?.forEach(e => ar.push(e));
35
- const t = () => ar.at(-1)?.();
36
53
  if (ms) {
37
54
  (mapWait.get(a) || mapWait.set(a, waitRun()).get(a))
38
55
  .refreshAsync(ms, () => {
39
56
  mapWait.delete(a);
40
- t();
57
+ triggerUpdate(a, false, true);
41
58
  });
42
59
  }
43
60
  else
44
- t();
61
+ triggerUpdate(a, false, true);
45
62
  }
46
- // Главная функция
47
63
  export function useUpdateBy(a, f) {
48
- const [_, setCounter] = useState(0); // Состояние счётчика для обновлений
49
- // Эффект для работы с объектом и картой
64
+ useSyncExternalStore((listener) => {
65
+ if (f)
66
+ return () => { };
67
+ const state = getObserverState(a);
68
+ state.listeners.add(listener);
69
+ return () => {
70
+ state.listeners.delete(listener);
71
+ if (state.listeners.size === 0)
72
+ map3.delete(a);
73
+ };
74
+ }, () => (f ? 0 : getObserverState(a).version));
50
75
  useLayoutEffect(() => {
51
- // Если передан второй аргумент `f`, используем его, иначе создаём default-функцию
52
- const func = f ?? (() => {
53
- setCounter(prev => prev + 1);
54
- });
55
- // Получаем карту из глобальной переменной map3 или создаём новую для объекта `a`
56
- const funcMap = map3.get(a) || map3.set(a, new Map()).get(a);
57
- funcMap.set(func, func); // Привязываем функцию обновления к объекту `a`
58
- // Возвращаем функцию очистки (cleanup), чтобы удалить привязки
76
+ if (!f)
77
+ return;
78
+ const state = getObserverState(a);
79
+ state.listeners.add(f);
59
80
  return () => {
60
- funcMap.delete(func); // Удаляем функцию из карты
61
- if (funcMap.size === 0) {
62
- map3.delete(a); // Удаляем объект из `map3`, если он больше не нужен
63
- }
81
+ state.listeners.delete(f);
82
+ if (state.listeners.size === 0)
83
+ map3.delete(a);
64
84
  };
65
- }, [a, f]); // Указываем зависимости: объект `a` и функция `f`
85
+ }, [a, f]);
66
86
  }
67
- // Backward-compatible name (hook rules are the same).
68
87
  export function updateBy(a, f) {
69
- return useUpdateBy(a, f);
88
+ useUpdateBy(a, f);
70
89
  }
71
- // export function updateBy<T extends object>(a: T, f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)) {
72
- // const t = useState(0)
90
+ // import {useLayoutEffect, useState} from "react";
91
+ // import {waitRun} from "wenay-common2";
92
+ //
93
+ // type tFunc2 = Map<object, (a?: any) => void>
94
+ // export const map3 = new WeakMap<object, tFunc2>();
95
+ // export const mapWait = new Map<object, ReturnType<typeof waitRun>>();
96
+ //
97
+ //
98
+ // export function renderBy(a: object, ms?: number) {
99
+ // const t = () => map3.get(a)?.forEach(e=>e(a))
100
+ // if (ms) {
101
+ // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
102
+ // .refreshAsync(ms, ()=> {
103
+ // mapWait.delete(a)
104
+ // t()})
105
+ // }
106
+ // else t()
107
+ // }
108
+ //
109
+ // export function renderByRevers(a: object, ms?: number, reverse = true) {
110
+ // const ar: ((a?: any) => void)[] = []
111
+ // map3.get(a)?.forEach(e=>ar.push(e))
112
+ // const t = reverse ? () => ar.reverse().forEach(e=>e(a))
113
+ // : () => ar.forEach(e=>e(a))
114
+ // if (ms) {
115
+ // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
116
+ // .refreshAsync(ms, ()=> {
117
+ // mapWait.delete(a)
118
+ // t()})
119
+ // }
120
+ // else t()
121
+ // }
122
+ //
123
+ // export function renderByLast(a: object, ms?: number) {
124
+ // const ar: ((a?: any) => void)[] = []
125
+ // map3.get(a)?.forEach(e=>ar.push(e))
126
+ // const t = () => ar.at(-1)?.()
127
+ // if (ms) {
128
+ // (mapWait.get(a) || mapWait.set(a, waitRun()).get(a)!)
129
+ // .refreshAsync(ms, ()=> {
130
+ // mapWait.delete(a)
131
+ // t()})
132
+ // }
133
+ // else t()
134
+ // }
135
+ //
136
+ // // Главная функция
137
+ // export function useUpdateBy<T extends object>(
138
+ // a: T,
139
+ // f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)
140
+ // ) {
141
+ // const [_, setCounter] = useState(0); // Состояние счётчика для обновлений
142
+ //
143
+ // // Эффект для работы с объектом и картой
73
144
  // useLayoutEffect(() => {
74
- // const func = f ?? ((a: T) =>{
75
- // // без особых причин только для первого рендера - необходима два вызова, иначе - вызов не проходит
76
- // if (t[0] == 0) {
77
- // t[1](t[0]++)
78
- // // t[1](t[0]++)
145
+ // // Если передан второй аргумент `f`, используем его, иначе создаём default-функцию
146
+ // const func = f ?? (() => {
147
+ // setCounter(prev => prev + 1);
148
+ // });
149
+ //
150
+ // // Получаем карту из глобальной переменной map3 или создаём новую для объекта `a`
151
+ // const funcMap = map3.get(a) || map3.set(a, new Map()).get(a)!;
152
+ // funcMap.set(func, func); // Привязываем функцию обновления к объекту `a`
153
+ //
154
+ // // Возвращаем функцию очистки (cleanup), чтобы удалить привязки
155
+ // return () => {
156
+ // funcMap.delete(func); // Удаляем функцию из карты
157
+ // if (funcMap.size === 0) {
158
+ // map3.delete(a); // Удаляем объект из `map3`, если он больше не нужен
79
159
  // }
80
- // else t[1](t[0]++)
81
- // })
82
- // const r = (map3.get(a) || map3.set(a, new Map()).get(a)!)
83
- // r.set(func, func)
84
- // return ()=> {
85
- // r?.delete(func)
86
- // }
87
- // },[true])
160
+ // };
161
+ // }, [a, f]); // Указываем зависимости: объект `a` и функция `f`
162
+ // }
163
+ //
164
+ // // Backward-compatible name (hook rules are the same).
165
+ // export function updateBy<T extends object>(
166
+ // a: T,
167
+ // f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)
168
+ // ) {
169
+ // return useUpdateBy(a, f);
88
170
  // }
171
+ //
172
+ // // export function updateBy<T extends object>(a: T, f?: React.Dispatch<React.SetStateAction<T>> | ((a: T) => void)) {
173
+ // // const t = useState(0)
174
+ // // useLayoutEffect(() => {
175
+ // // const func = f ?? ((a: T) =>{
176
+ // // // без особых причин только для первого рендера - необходима два вызова, иначе - вызов не проходит
177
+ // // if (t[0] == 0) {
178
+ // // t[1](t[0]++)
179
+ // // // t[1](t[0]++)
180
+ // // }
181
+ // // else t[1](t[0]++)
182
+ // // })
183
+ // // const r = (map3.get(a) || map3.set(a, new Map()).get(a)!)
184
+ // // r.set(func, func)
185
+ // // return ()=> {
186
+ // // r?.delete(func)
187
+ // // }
188
+ // // },[true])
189
+ // // }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wenay-react2",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Common react",
5
5
  "strict": true,
6
6
  "main": "dist/index.js",