Query
The useQuery
composable allow you to read any data from chain, while maintaining updates, concurrency, caching & deduplication behind the scene for you.
Async handling
useQuery
utilize Vue's Suspense API for data fetching & error handling.
<script setup lang="ts">
const { data: activeEra } = await useQuery((builder) =>
builder.readStorage("Staking", "ActiveEra", []),
);
</script>
<template>
<div>Active era: {{ activeEra.toLocaleString() }}</div>
</template>
<script setup lang="ts">
import AsyncComponent from "./async-component.vue";
import { onErrorCaptured } from "vue";
onErrorCaptured((error) => console.log(error));
</script>
<template>
<Suspense>
<AsyncComponent />
<template #fallback>Loading...</template>
</Suspense>
</template>
Fetching multiple data
Fetching multiple data can be done by chaining queries together, useQuery
(with TypeScript) will automatically infer that you want to fetch multiple data concurrently & will return an array of data instead.
<script setup lang="ts">
import { useQuery } from "@reactive-dot/vue";
import { computed } from "vue";
const { data } = await useQuery((builder) =>
builder
.getConstant("Babe", "ExpectedBlockTime")
.getConstant("Babe", "EpochDuration")
.readStorage("Treasury", "ProposalCount", []),
);
const expectedBlockTime = computed(() => data.value[0]);
const epochDuration = computed(() => data.value[1]);
const proposalCount = computed(() => data.value[2]);
</script>
Multiple queries of the same type can also be fetched using callApis
& readStorages
.
<script setup lang="ts">
import { useQuery } from "@reactive-dot/vue";
const { data } = await useQuery((builder) =>
builder
.callApis("NominationPoolsApi", "pending_rewards", [
[ADDRESS_1],
[ADDRESS_2],
[ADDRESS_3],
])
.readStorages("NominationPools", "Metadata", [
[POOL_ID_1],
[POOL_ID_2],
[POOL_ID_3],
]),
);
</script>
Conditional query
Use a falsy value (undefined
, null
or false
) to conditionally fetch data. If the query builder returns a falsy value, ReactiveDOT will not execute the query.
<script setup lang="ts">
import { useQuery } from "@reactive-dot/vue";
const { status } = await useQuery((builder) =>
address.value === undefined
? undefined
: builder.callApi("NominationPoolsApi", "pending_rewards", [address.value]),
);
// Status will be "idle" if the query hasn't been executed
if (status === "idle") {
console.log("The query is in idle state");
}
</script>
Refreshing queries
Certain query, like runtime API calls & reading of storage entries doesn't create any subscriptions. In order to get the latest data, they must be manually refreshed.
<script setup lang="ts">
import { useQuery } from "@reactive-dot/vue";
const {
data: pendingRewards,
refresh,
status,
} = await useQuery((builder) =>
builder.callApi("NominationPoolsApi", "pending_rewards", [ACCOUNT_ADDRESS]),
);
</script>
<template>
<div>
<p>{{ pendingRewards.toLocaleString() }}</p>
<button @click="refresh()" :disabled="status === 'pending'">Refresh</button>
</div>
</template>
Retry failed query
Error from queries can be reset using ErrorBoundary
& useQueryErrorResetter
composable.
<script setup lang="ts">
import { useQueryErrorResetter } from "@reactive-dot/vue";
import { onErrorCaptured, ref } from "vue";
const hasError = ref(false);
const { execute: resetError } = useQueryErrorResetter();
onErrorCaptured(() => (hasError.value = true));
</script>
<template>
<article v-if="hasError">
<header>
<strong>Oops, something went wrong!</strong>
</header>
<button
@click="
resetError();
hasError = false;
"
>
Retry
</button>
</article>
<Suspense v-else>
<MyDApp />
<template #fallback>Loading...</template>
</Suspense>
</template>