useTina()
Composable utama buat konsumsi data TinaCMS dengan update reaktif secara real-time.
Type signature
function useTina<T extends Record<string, unknown>>(
props: UseTinaOptions<T> | Ref<any> | ComputedRef<any>
): UseTinaReturn<T>
Kamu bisa pass objek options, atau ref langsung, termasuk seluruh ref yang dibalikin useAsyncData/useFetch (lihat contoh di bawah).
Parameter: props (sebagai UseTinaOptions<T>)
| Properti | Tipe | Wajib | Deskripsi |
|---|---|---|---|
data | T | Nggak | Data awal, dari SSR, panggilan API, atau query Tina. |
query | string | Nggak | String query GraphQL Tina, dibutuhkan buat handshake visual-editing. |
variables | Record<string, unknown> | Nggak | Variable GraphQL buat query-nya. |
Return value
| Properti | Tipe | Deskripsi |
|---|---|---|
data | Ref<T> | Data reaktif, otomatis update pas form di Tina Admin berubah. |
isEditing | Ref<boolean> | true pas halamannya dibuka di mode editing/preview. |
isInIframe | Ref<boolean> | true pas halamannya dimuat di dalam iframe Tina Admin. |
quickEditEnabled | Ref<boolean> | true selama mode quick-edit (klik-buat-edit) diaktifin dari Tina Admin. |
bridgeError | Ref<Error | null> | Error terakhir yang ketangkep pas komunikasi sama Tina Admin, atau null kalau nggak ada yang gagal. Sama-sama dipakai dengan useTinaBridge(). |
refresh | () => Promise<void> | Maksa refreshNuxtData(). Dipakai setelah event save yang beneran. |
tinaField(object, property?, index?)
Helper yang bikin attribute data-tina-field, jadi Tina Admin tau elemen DOM mana yang representasiin field mana.
<h1 :data-tina-field="tinaField(post, 'title')">{{ post.title }}</h1>
<!-- buat item di dalam list, sertain index-nya -->
<span
v-for="(tag, idx) in post.tags"
:key="idx"
:data-tina-field="tinaField(post, 'tags', idx)"
>{{ tag }}</span>
object-nya harus dari data yang dibalikin useTina() (bukan data mentah sebelum diproses), di situ metadata _content_source yang dibutuhkan tinaField() nempel.
Contoh pemakaian
useTina() nerima ref response server yang lengkap (bukan cuma data yang udah di-unwrap). Dia butuh query dan variables di dalamnya buat kirim handshake ke Tina Admin. Cara paling gampang: tulis server route yang panggil tina/__generated__/client, terus pass ref hasil useAsyncData langsung ke useTina().
// server/api/posts/[slug].get.ts
import client from '../../../tina/__generated__/client'
export default defineEventHandler(async (event) => {
const relativePath = `${getRouterParam(event, 'slug')}.md`
const res = await client.queries.post({ relativePath })
return { data: res.data, query: res.query, variables: res.variables }
})
<script setup lang="ts">
const route = useRoute()
const { data: response } = await useAsyncData(`post-${route.params.slug}`, () =>
$fetch(`/api/posts/${route.params.slug}`),
)
const { data, isEditing, isInIframe } = useTina(response)
const post = computed(() => data.value?.post ?? {})
</script>
<template>
<article>
<div v-if="isInIframe" class="edit-badge">Tina Contextual Editing Active</div>
<h1 :data-tina-field="tinaField(post, 'title')">{{ post.title }}</h1>
<p :data-tina-field="tinaField(post, 'description')">{{ post.description }}</p>
</article>
</template>