# useLive()

Async rendering of remotely triggered data mutations.

[useSuspense()](https://dataclient.io/docs/api/useSuspense.md) + [useSubscription()](https://dataclient.io/docs/api/useSubscription.md) in one hook.

`useLive()` is reactive to data [mutations](https://dataclient.io/docs/getting-started/mutations.md); rerendering only when necessary.

## Usage

```typescript title="Ticker" {33}
import { Entity, RestEndpoint } from '@data-client/rest';
import { Temporal } from 'temporal-polyfill';

export class Ticker extends Entity {
  product_id = '';
  trade_id = 0;
  price = 0;
  size = '0';
  time = Temporal.Instant.fromEpochMilliseconds(0);
  bid = '0';
  ask = '0';
  volume = '';

  pk(): string {
    return this.product_id;
  }
  static key = 'Ticker';

  static schema = {
    price: Number,
    time: Temporal.Instant.from,
  };
}

export const getTicker = new RestEndpoint({
  urlPrefix: 'https://api.exchange.coinbase.com',
  path: '/products/:productId/ticker',
  schema: Ticker,
  process(value, { productId }) {
    value.product_id = productId;
    return value;
  },
  pollFrequency: 2000,
});
```

```tsx title="AssetPrice" {5}
import { useLive } from '@data-client/react';
import NumberFlow from '@number-flow/react';
import { getTicker } from './Ticker';

function AssetPrice({ productId }: Props) {
  const ticker = useLive(getTicker, { productId });
  return (
    <center>
      {productId}{' '}
      <NumberFlow
        value={ticker.price}
        format={{ style: 'currency', currency: 'USD' }}
      />
    </center>
  );
}
interface Props {
  productId: string;
}
render(<AssetPrice productId="BTC-USD" />);
```

## 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 = useLive(TodoResource.get, id ? { id } : null);
> ```

> **Info: React Native**
>
> When using React Navigation, useLive() will trigger fetches on focus if the data is considered
> stale. useLive() will also sub/unsub with focus/unfocus respectively.

## Types

```typescript
function useLive(
  endpoint: ReadEndpoint,
  ...args: Parameters<typeof endpoint> | [null]
): Denormalize<typeof endpoint.schema>;
```

```typescript
function useLive<
  E extends EndpointInterface<
    FetchFunction,
    Schema | undefined,
    undefined
  >,
  Args extends readonly [...Parameters<E>] | readonly [null],
>(
  endpoint: E,
  ...args: Args
): E['schema'] extends Exclude<Schema, null>
  ? Denormalize<E['schema']>
  : ReturnType<E>;
```

## Examples

### Bitcoin Price (polling)

When our component with `useLive` is rendered, `getTicker` will fetch at [pollFrequency](https://dataclient.io/rest/api/RestEndpoint.md#pollfrequency)
milliseconds.

Example app: [nextjs](https://github.com/reactive/data-client/tree/master/examples/nextjs) ([`resources/Ticker.ts`](https://github.com/reactive/data-client/blob/master/examples/nextjs/resources/Ticker.ts), [`components/AssetPrice.tsx`](https://github.com/reactive/data-client/blob/master/examples/nextjs/components/AssetPrice.tsx))
