# useCache()

Data rendering without the fetch.

Access any [Endpoint](https://dataclient.io/rest/api/Endpoint.md)'s response. If the response does not exist, returns
`undefined`. This can be used to check for an `Endpoint's` existence like for authentication.

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

## Usage

```ts title="UserResource"
import { Entity, resource } from '@data-client/rest';

export class User extends Entity {
  id = '';
  name = '';
  isAdmin = false;

  static key = 'User';
}
export const UserResource = resource({
  path: '/users/:id',
  schema: User,
}).extend('current', {
  path: '/user',
  schema: User,
});
```

```html title="Unauthed.vue"
<script setup lang="ts">
  import { useController, useLoading } from '@data-client/vue';
  import { UserResource } from './UserResource';

  const ctrl = useController();
  const [handleLogin, loading] = useLoading(() =>
    ctrl.fetch(UserResource.current),
  );
</script>

<template>
  <div>
    <p>Not authorized</p>
    <template v-if="loading">logging in...</template>
    <button v-else @click="handleLogin">Login</button>
  </div>
</template>
```

```html title="Authorized.vue"
<script setup lang="ts">
  import { useController } from '@data-client/vue';
  import { UserResource, type User } from './UserResource';

  defineProps<{ user: User }>();
  const ctrl = useController();
  const handleLogout = () => ctrl.invalidate(UserResource.current);
</script>

<template>
  <div>
    <p>Welcome, {{ user.name }}!</p>
    <button @click="handleLogout">Logout</button>
  </div>
</template>
```

```html title="AuthorizedPage.vue"
<script setup lang="ts">
  import { useCache } from '@data-client/vue';
  import { UserResource } from './UserResource';
  import Unauthed from './Unauthed.vue';
  import Authorized from './Authorized.vue';

  // currentUser as ComputedRef<User | undefined>
  const currentUser = useCache(UserResource.current);
</script>

<template>
  <!-- currentUser is unwrapped in the template -->
  <Authorized v-if="currentUser" :user="currentUser" />
  <!-- user is not logged in -->
  <Unauthed v-else />
</template>
```

See [truthiness narrowing](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#truthiness-narrowing) for
more information about type handling

## Behavior

`useCache()` returns a [ComputedRef](https://vuejs.org/api/reactivity-core.html#computed). The table
below describes its `.value`.

| Expiry Status | Returns      | Conditions                                                                                                                                                                                                                                        |
| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Invalid       | `undefined`  | not in store, [deletion](https://dataclient.io/rest/api/resource.md#delete), [invalidation](https://dataclient.io/vue/api/Controller.md#invalidate), [invalidIfStale](https://dataclient.io/vue/concepts/expiry-policy.md#endpointinvalidifstale) |
| Stale         | denormalized | (first-render, arg change) & [expiry < now](https://dataclient.io/vue/concepts/expiry-policy.md)                                                                                                                                                  |
| Valid         | denormalized | fetch completion                                                                                                                                                                                                                                  |
|               | `undefined`  | `null` used as second argument                                                                                                                                                                                                                    |

> **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 = useCache(
>   TodoResource.get,
>   computed(() => (id.value ? { id: id.value } : null)),
> );
> ```

## Types

```typescript
function useCache(
  endpoint: ReadEndpoint,
  ...args: MaybeRefsOrGetters<Parameters<typeof endpoint.key>> | [null]
): ComputedRef<DenormalizeNullable<typeof endpoint.schema>>;
```

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.

The result updates when the arguments change.
