Skip to content

useSyncObservableArray

Reactive synchronization between a reactive array with ObservableArray.

Generate an ObservableArray that will listen for changes in a reactive Vue array and apply them to the ObservableArray. Useful to use together with ListView and UI-CollectionView

Usage

With reactivity

vue
<script lang="ts" setup>
import { ref } from "nativescript-vue";
import { useSyncObservableArray } from "@nativescript-use/vue";

const myArrayRef = ref([{id: 1, foo: "bar"}]);
const { observableArray } = useSyncObservableArray<MyType>(
  myArrayRef, 
  { 
    addRemoveByField: "id", 
    watchUpdates: true  // <-- default is false 
  } 
);

function updateData(){
  myArrayRef.value[0].foo = "lorem";
}
</script>

Without reactivity (manual synchronization)

vue
<script lang="ts" setup>
import { useSyncObservableArray } from "@nativescript-use/vue";

const myArrayRef = ref([{id: 1, foo: "bar"}]);
const { sync, observableArray } = useSyncObservableArray<MyType>(
  myArrayRef, 
  { addRemoveByField: "id" } 
);

function updateData(){
  myArrayRef.value[0].foo = "lorem";
  sync();
}
</script>

Performance

Keep in mind that searching for changes in very large arrays is expensive so keep these points in mind when using useSyncObservableArray.

  • Use addRemoveByField to indicate a unique property of each array element, for example the id.
  • The process to search for changes consists of 3 phases:
    • Search for deleted items. Option checkRemoved.
    • Search for added items. Option checkAdded.
    • Check for updates on items. Option checkUpdates.

By default all 3 phases are activated. Use these parameters to indicate which operations you want to detect. An example, if you only want to track updates, use the following configuration:

vue
<script lang="ts" setup>
const { observableArray } = useSyncObservableArray<MyType>(
  myArrayRef, 
  { 
    addRemoveByField: "id",
    checkRemoved: false,
    checkAdded: false,
    checkUpdates: true
  } 
);
</script>

pushAllInFirstSync

WARNING

@Deprecated from v0.0.46

ObservableArray will sync without checking for differences if it is empty. This improves performance and this option is no longer needed.

A typical case is to declare a reactive array next to useSyncObservableArray and then make a request to a service to bring us all the information. In this scenario, the fastest thing is to directly synchronize the ObservableArray without checking for updates. With the property pushAllInFirstSync: true we indicate that the data is inserted in the first synchronization

Hooks

onPreUpdate

To have native performance in Lists/CollectionView, the recycling of items provided by Android/iOS is implemented. When we use these views from vue, the normal thing is to access calculated properties in our template, this causes a loss of performance when the calculation carried out is slow. To mitigate this we must calculate the field before adding it to the ObservableArray, for this we have the onPreUpdate hook, it allows the object to be mutated before adding it to the ObservableArray (this mutation will not affect its reactive object).

Note that in this case the scrolling will be fast, but the initial loading of the data will be slower since it performs the calculation before inserting the elements.

❌ Don't do this

vue
<script lang="ts" setup>
import { useSyncObservableArray } from "@nativescript-use/vue";
import TextService from "...";

const { observableArray } = useSyncObservableArray<MyType>(myArrayRef);

function getText(item: MyType){
  return TextService.buildTitleText(item);
}
</script>
<template>
  <CollectionView :items="observableArray">
    <template #default="{ item } : { item: MyType }">
      <Label :text="getText(item)" />
    </template>
  </CollectionView>
</template>

✅ Do this

vue

<script lang="ts" setup>
import { useSyncObservableArray } from "@nativescript-use/vue";
import TextService from "...";

const { observableArray } = useSyncObservableArray<MyType, MyObservableType>(myArrayRef, {
    onPreUpdate(item: MyType, index: number, updateType: OnPreupdateType){
      item.title = TextService.buildTitleText(item);
      return item;
    }
  }
);
</script>
<template>
  <CollectionView :items="observableArray">
    <template #default="{ item } : { item: MyObservableType }">
      <Label :text="item.title" />
    </template>
  </CollectionView>
</template>

Source

Type declaration

ts
import { ObservableArray } from "@nativescript/core";
import { Ref } from "nativescript-vue";
/**
 * Reactive synchronization between a reactive array with ObservableArray.
 *
 * @param arrayWatchTarget
 * @param options
 */

export declare function useSyncObservableArray<T, J = any>(arrayRef: Ref<T[]> | T[], options?: {
   addRemoveByField?: string;
    excludeCompareFields?: string[];
    watchUpdates?: boolean;
    checkRemoved?: boolean;
    checkAdded?: boolean;
    checkUpdates?: boolean;
    pushAllInFirstSync?: boolean;
    initialDelay?: number;
    onPushInitialData?: () => void;
    onPreUpdate?: preUpdate<T, J>;
}): {
    sync: (newArray?: Ref<T[]> | T[]) => void;
    observableArray: ObservableArray<T>;
};