# useSubscription()

Great for keeping resources up-to-date with frequent changes.

When using the default [polling subscriptions](https://dataclient.io/vue/api/PollingSubscription.md), frequency must be set in
[Endpoint](https://dataclient.io/rest/api/Endpoint.md), otherwise will have no effect.

> **Tip**
>
> [useLive()](https://dataclient.io/vue/api/useLive.md) is a terser way to use in combination with [useSuspense()](https://dataclient.io/vue/api/useSuspense.md),

## Usage

```typescript title="api/Price"
import { RestEndpoint, Entity } from '@data-client/rest';

export class Price extends Entity {
  symbol = '';
  price = '0.0';
  // ...

  pk() {
    return this.symbol;
  }
}

export const getPrice = new RestEndpoint({
  urlPrefix: 'http://test.com',
  path: '/price/:symbol',
  schema: Price,
  pollFrequency: 5000,
});
```

```html title="MasterPrice.vue"
<script setup lang="ts">
  import { useSuspense, useSubscription } from '@data-client/vue';
  import { getPrice } from 'api/Price';

  const props = defineProps<{ symbol: string }>();
  const price = await useSuspense(getPrice, () => ({ symbol: props.symbol }));
  useSubscription(getPrice, () => ({ symbol: props.symbol }));
  // ...
</script>
```

## Behavior

> **Tip: Conditional Dependencies**
>
> Use `null` as the second argument to any Data Client hook means "do nothing."
>
> ```typescript
> // todo could be undefined if id is undefined
> const todo = useSubscription(
>   TodoResource.get,
>   computed(() => (id.value ? { id: id.value } : null)),
> );
> ```

The subscription is created when the component is set up and removed when it unmounts. When
an argument passed as a [ref](https://vuejs.org/api/reactivity-core.html#ref) changes, the previous
subscription is removed and a new one is created for the new arguments.

## Types

```typescript
function useSubscription(
  endpoint: ReadEndpoint,
  ...args: MaybeRefsOrGetters<Parameters<typeof endpoint>> | [null]
): void;
```

Arguments can be plain values, [refs](https://vuejs.org/api/reactivity-core.html#ref) (including [computed](https://vuejs.org/api/reactivity-core.html#computed)), or getter
functions like `() => ({ id: props.id })`. A plain object like `{ id: props.id }` is read once and won't
follow prop or route changes, so use a getter or `computed` when an argument can change.

## Examples

### Only subscribe while element is visible

```html title="MasterPrice.vue"
<script setup lang="ts">
  import { computed, useTemplateRef } from 'vue';
  import { useElementVisibility } from '@vueuse/core';
  import { useSuspense, useSubscription } from '@data-client/vue';
  import { getPrice } from 'api/Price';

  const props = defineProps<{ symbol: string }>();
  const price = await useSuspense(getPrice, () => ({ symbol: props.symbol }));
  const el = useTemplateRef('el');
  const isVisible = useElementVisibility(el);
  // null params means don't subscribe
  useSubscription(
    getPrice,
    computed(() => (isVisible.value ? { symbol: props.symbol } : null)),
  );
</script>

<template>
  <div ref="el">{{ price.price }}</div>
</template>
```

When `null` is sent as the second argument, the subscription is deactivated. Of course,
if other components are still subscribed the data updates will still be active.

[useElementVisibility()](https://vueuse.org/core/useElementVisibility/) from VueUse uses [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API), which is very performant. [Template refs](https://vuejs.org/guide/essentials/template-refs.html) allow
us to access the [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model).
