@xen-orchestra/web-core 0.48.0 → 0.48.2

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.
@@ -48,6 +48,48 @@ const useMyResource = defineRemoteResource({
48
48
  const { myResource, customProp } = useMyResource()
49
49
  ```
50
50
 
51
+ ### State
52
+
53
+ When managing arrays, avoid using `computed` inside the `state` function. This can cause performance issues because each call to `computed` will perform a full iteration over `data` every time it's updated. For example, for a large collection of 10,000 elements, three calls to `computed` based on `data` will generate 30,000 iterations. Instead, use `watch` and a `forEach` loop, and distribute your data across multiple references (`ref`) so that `data` is only iterated over once with each modification.
54
+
55
+ ```typescript
56
+ const useMyResource = defineRemoteResource({
57
+ url: '/api/path/to/resource',
58
+ initialData: () => [] as MyResource[],
59
+ state: (data) => {
60
+ const filteredResources = ref<MyResource[]>([])
61
+ const anotherFilteredResources = ref<MyResource[]>([])
62
+
63
+ watch(data, _data => {
64
+ const tmpFilteredResources: MyResource[] = []
65
+ const tmpAnotherFilteredResources: MyResource[] = []
66
+
67
+ _data.forEach(value => {
68
+ if(value.foo === 'Foo'){
69
+ tmpFilteredResources.push(value)
70
+ } else if (value.foo === 'Bar'){
71
+ tmpAnotherFilteredResources.push(value)
72
+ }
73
+ })
74
+
75
+ filteredResources.value = tmpFilteredResources
76
+ anotherFilteredResources.value = tmpAnotherFilteredResources
77
+ })
78
+
79
+ return {
80
+ myResource: data,
81
+ filteredResources,
82
+ anotherFilteredResources
83
+ }
84
+ },
85
+ onDataReceived: (currentData, receivedData) => {
86
+ deepMerge(currentData.value, receivedData)
87
+ }
88
+ }
89
+
90
+
91
+ ```
92
+
51
93
  ## Context
52
94
 
53
95
  The context is available in the `$context` property of the returned state.
@@ -7,7 +7,7 @@ import {
7
7
  import type { ResourceContext, UseRemoteResource } from '@core/packages/remote-resource/types.ts'
8
8
  import type { VoidFunction } from '@core/types/utility.type.ts'
9
9
  import { ifElse } from '@core/utils/if-else.utils.ts'
10
- import { type MaybeRef, noop, useTimeoutPoll } from '@vueuse/core'
10
+ import { type MaybeRef, noop, useDebounceFn, useTimeoutPoll } from '@vueuse/core'
11
11
  import { merge, remove } from 'lodash-es'
12
12
  import readNDJSONStream from 'ndjson-readablestream'
13
13
  import {
@@ -20,6 +20,8 @@ import {
20
20
  reactive,
21
21
  type Ref,
22
22
  ref,
23
+ shallowRef,
24
+ triggerRef,
23
25
  toRef,
24
26
  toValue,
25
27
  watch,
@@ -255,7 +257,20 @@ export function defineRemoteResource<
255
257
 
256
258
  const hasError = computed(() => lastError.value !== undefined)
257
259
 
258
- const data = ref(buildData()) as Ref<TData>
260
+ const data = shallowRef(buildData()) as Ref<TData>
261
+ // trigger reactivity on data when no more updates since 100ms or after 500ms
262
+ const flushData = useDebounceFn(
263
+ () => {
264
+ if (Array.isArray(data.value)) {
265
+ triggerRef(data)
266
+ } else if (data.value != null) {
267
+ // create a new JS reference to ensure vueJS detect the change
268
+ data.value = { ...data.value }
269
+ }
270
+ },
271
+ 100,
272
+ { maxWait: 500 }
273
+ )
259
274
 
260
275
  async function execute() {
261
276
  try {
@@ -275,9 +290,11 @@ export function defineRemoteResource<
275
290
  if (config.stream) {
276
291
  for await (const event of readNDJSONStream(response.body)) {
277
292
  onDataReceived(data, event)
293
+ flushData()
278
294
  }
279
295
  } else {
280
296
  onDataReceived(data, await response.json())
297
+ flushData()
281
298
  }
282
299
 
283
300
  isReady.value = true
@@ -302,8 +319,14 @@ export function defineRemoteResource<
302
319
  handleWatching,
303
320
  handlePost,
304
321
  resource,
305
- onDataReceived: receivedData => onDataReceived(data, receivedData, context),
306
- onDataRemoved: receivedData => onDataRemoved(data, receivedData, context),
322
+ onDataReceived: receivedData => {
323
+ onDataReceived(data, receivedData, context)
324
+ flushData()
325
+ },
326
+ onDataRemoved: receivedData => {
327
+ onDataRemoved(data, receivedData, context)
328
+ flushData()
329
+ },
307
330
  })
308
331
  await execute()
309
332
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@xen-orchestra/web-core",
3
3
  "type": "module",
4
- "version": "0.48.0",
4
+ "version": "0.48.2",
5
5
  "private": false,
6
6
  "exports": {
7
7
  "./*": {