@fozy-labs/rx-toolkit 0.4.5 → 0.4.7

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 fozykit
3
+ Copyright (c) 2025 Vladimir Panev
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
@@ -137,6 +137,9 @@ export class Operation {
137
137
  if (link.create && !ref.has) {
138
138
  ref.create(link.create({ args, data }));
139
139
  }
140
+ if (link.invalidate) {
141
+ ref.invalidate();
142
+ }
140
143
  state.patch?.commit();
141
144
  });
142
145
  hookResolvers.fulfilledSuccess(data);
@@ -41,6 +41,9 @@ export declare class Resource<D extends ResourceDefinition> implements ResourceI
41
41
  }, options?: {
42
42
  cache?: CoreResourceQueryCache<D>;
43
43
  }): CoreResourceQueryCache<D> | null;
44
+ createWithData(args: D['Args'], data: D['Data'], options?: {
45
+ cache?: CoreResourceQueryCache<D>;
46
+ }): CoreResourceQueryCache<D>;
44
47
  initiate(args: D['Args'], options?: {
45
48
  cache?: CoreResourceQueryCache<D>;
46
49
  }): CoreResourceQueryCache<D>;
@@ -24,6 +24,7 @@ class ResourceQueryState {
24
24
  static load(state = ResourceQueryState.create(), args) {
25
25
  return {
26
26
  ...state,
27
+ abortController: new AbortController(),
27
28
  args: args,
28
29
  isLoading: !state.isDone,
29
30
  isReloading: state.isDone,
@@ -33,6 +34,7 @@ class ResourceQueryState {
33
34
  static success(state, data) {
34
35
  return {
35
36
  ...state,
37
+ abortController: null,
36
38
  savedData: null,
37
39
  transactions: null,
38
40
  data,
@@ -47,6 +49,7 @@ class ResourceQueryState {
47
49
  static error(state, error) {
48
50
  return {
49
51
  ...state,
52
+ abortController: null,
50
53
  isLoading: false,
51
54
  isReloading: false,
52
55
  isDone: true,
@@ -79,14 +82,22 @@ class ResourceQueryState {
79
82
  data
80
83
  };
81
84
  }
82
- /**
83
- * @deprecated
84
- */
85
- static setData(state, data) {
85
+ static createWithData(data, args) {
86
86
  return {
87
- ...state,
87
+ savedData: null,
88
88
  transactions: null,
89
- data
89
+ data,
90
+ isLoading: false,
91
+ isReloading: false,
92
+ isDone: true,
93
+ isSuccess: true,
94
+ isError: false,
95
+ error: null,
96
+ abortController: null,
97
+ args,
98
+ isInitiated: false,
99
+ isLocked: false,
100
+ lockCount: 0
90
101
  };
91
102
  }
92
103
  }
@@ -155,8 +166,22 @@ export class Resource {
155
166
  cache.next(ResourceQueryState.update(cache.value, data, savedData, transactions));
156
167
  return cache;
157
168
  }
169
+ createWithData(args, data, options) {
170
+ let cache = options?.cache ?? this.getQueryCache(args);
171
+ const state = ResourceQueryState.createWithData(data, args);
172
+ if (!cache) {
173
+ cache = this.createQueryCache(args, state);
174
+ // Только обновляем кэш новыми данными, если он еще не был инициализирован.
175
+ // Это предотвращает перезапись уже инициализированного кэша.
176
+ }
177
+ else if (!cache.value.isInitiated) {
178
+ cache.next(state);
179
+ }
180
+ return cache;
181
+ }
158
182
  initiate(args, options) {
159
183
  let cache = options?.cache ?? this.getQueryCache(args);
184
+ const prevAbortController = cache?.value.abortController ?? null;
160
185
  const state = ResourceQueryState.load(cache?.value, args);
161
186
  if (!cache) {
162
187
  cache = this.createQueryCache(args, state);
@@ -164,9 +189,8 @@ export class Resource {
164
189
  else {
165
190
  cache.next(state);
166
191
  }
167
- let abortController = state.abortController;
168
- abortController?.abort();
169
- abortController = new AbortController();
192
+ prevAbortController?.abort();
193
+ const abortController = state.abortController;
170
194
  const query = this._options.queryFn(args, { abortSignal: abortController.signal });
171
195
  const hookResolvers = this._hooks.onQueryStarted(args);
172
196
  query
@@ -174,7 +198,7 @@ export class Resource {
174
198
  if (abortController.signal.aborted) {
175
199
  return;
176
200
  }
177
- const data = this._options.select ? result._options.select(result) : result;
201
+ const data = this._options.select ? this._options.select(result) : result;
178
202
  cache.next(ResourceQueryState.success(state, data));
179
203
  hookResolvers.fulfilledSuccess(data);
180
204
  })
@@ -128,9 +128,9 @@ export class ResourceRef {
128
128
  return transaction;
129
129
  }
130
130
  create(data) {
131
- throw new Error("Method not implemented.");
131
+ this._cacheItem = this._resource.createWithData(this._args, data, { cache: this._cacheItem ?? undefined });
132
132
  }
133
133
  invalidate() {
134
- throw new Error("Method not implemented.");
134
+ this._cacheItem = this._resource.initiate(this._args, { cache: this._cacheItem ?? undefined });
135
135
  }
136
136
  }
@@ -5,6 +5,7 @@ import { shallowEqual } from "../../query/lib/shallowEqual";
5
5
  import { SKIP } from "../../query/SKIP_TOKEN";
6
6
  export function useResourceAgent(res, ...argss) {
7
7
  const args = (argss[0] === SKIP ? SKIP : argss[0]);
8
+ const prevArgsRef = React.useRef(args);
8
9
  const agent = useConstant(() => {
9
10
  const agent = res.createAgent();
10
11
  if (args !== SKIP) {
@@ -12,16 +13,11 @@ export function useResourceAgent(res, ...argss) {
12
13
  }
13
14
  return agent;
14
15
  });
15
- React.useEffect(() => {
16
- if (args === SKIP) {
17
- return;
18
- }
19
- const state = agent.state$.peek();
20
- if (state.isInitiated && shallowEqual(args, state.args)) {
21
- return;
22
- }
16
+ const state = agent.state$.peek();
17
+ if (state.isInitiated && args !== SKIP && !shallowEqual(args, prevArgsRef.current)) {
18
+ prevArgsRef.current = args;
23
19
  agent.initiate(args);
24
- }, [args]);
20
+ }
25
21
  React.useEffect(() => () => {
26
22
  agent.complete();
27
23
  }, []);
@@ -1,5 +1,5 @@
1
1
  import { SKIP } from "../../query/SKIP_TOKEN";
2
2
  import type { Prettify, ResourceDefinition, ResourceInstance, ResourceRefInstanse } from "../../query/types";
3
- type Result<D extends ResourceDefinition> = Prettify<ResourceRefInstanse<D>> | null;
3
+ type Result<D extends ResourceDefinition> = Prettify<ResourceRefInstanse<D>>;
4
4
  export declare function useResourceRef<D extends ResourceDefinition>(res: ResourceInstance<D>, ...argss: D['Args'] extends void ? [] | [typeof SKIP] : [D['Args'] | typeof SKIP]): Result<D>;
5
5
  export {};
@@ -1,12 +1,23 @@
1
1
  import React from "react";
2
2
  import { useEventHandler } from "../../common/react";
3
3
  export function useSignal(signal$) {
4
+ const doUpdateRef = React.useRef(false);
4
5
  const subscribe = React.useCallback((update) => {
5
- const subscription = signal$.subscribe(update);
6
+ const subscription = signal$.subscribe(() => {
7
+ doUpdateRef.current = true;
8
+ queueMicrotask(() => {
9
+ if (!doUpdateRef.current)
10
+ return;
11
+ update();
12
+ });
13
+ });
6
14
  return () => {
7
15
  subscription.unsubscribe();
8
16
  };
9
17
  }, [signal$]);
10
- const getSnapshot = useEventHandler(() => signal$.peek());
18
+ const getSnapshot = useEventHandler(() => {
19
+ doUpdateRef.current = false;
20
+ return signal$.peek();
21
+ });
11
22
  return React.useSyncExternalStore(subscribe, getSnapshot);
12
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fozy-labs/rx-toolkit",
3
- "version": "0.4.5",
3
+ "version": "0.4.7",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "type": "module",