Chain a DataSource refetch
Call .then() on APICall.execute() to trigger a DataSource refetch after a mutation completes.
When a user action changes server data — liking a post, adding a comment — the displayed list needs to reflect the change. Because execute() returns a Promise, you can chain .then(() => dataSource.refetch()) to re-fetch the list as soon as the write succeeds — without relying on blanket cache invalidation.
<Component name="SocialButton">
<Button
borderRadius="50%"
icon="{$props.icon}"
variant="outlined"
themeColor="{$props.themeColor || 'secondary'}"
size="xs"
onClick="{emitEvent('click')}" />
</Component><App>
<APICall
id="favoritePost"
method="post"
url="/api/posts/{$param}/favorite" />
<APICall
id="unfavoritePost"
method="post"
url="/api/posts/{$param}/unfavorite" />
<DataSource
id="timelineData"
url="/api/timeline"
method="GET" />
<VStack>
<H3>Social Media Timeline</H3>
<Items data="{timelineData}">
<Card>
<VStack>
<H4>{$item.author}</H4>
<Text>{$item.content}</Text>
<HStack verticalAlignment="center">
<HStack verticalAlignment="center">
<SocialButton icon="reply" />
<Text>{$item.replies_count}</Text>
</HStack>
<HStack verticalAlignment="center">
<SocialButton icon="trending-up" />
<Text>{$item.reblogs_count}</Text>
</HStack>
<HStack verticalAlignment="center">
<SocialButton
icon='like'
themeColor="{$item.favourited ? 'attention' : 'secondary'}"
onClick="() => {
if ($item.favourited) {
unfavoritePost.execute($item.id)
timelineData.refetch();
} else {
favoritePost.execute($item.id)
timelineData.refetch();
}
}
" />
<Text variant="caption">{$item.favourites_count}</Text>
</HStack>
</HStack>
</VStack>
</Card>
</Items>
</VStack>
</App><Component name="SocialButton">
<Button
borderRadius="50%"
icon="{$props.icon}"
variant="outlined"
themeColor="{$props.themeColor || 'secondary'}"
size="xs"
onClick="{emitEvent('click')}" />
</Component><App>
<APICall
id="favoritePost"
method="post"
url="/api/posts/{$param}/favorite" />
<APICall
id="unfavoritePost"
method="post"
url="/api/posts/{$param}/unfavorite" />
<DataSource
id="timelineData"
url="/api/timeline"
method="GET" />
<VStack>
<H3>Social Media Timeline</H3>
<Items data="{timelineData}">
<Card>
<VStack>
<H4>{$item.author}</H4>
<Text>{$item.content}</Text>
<HStack verticalAlignment="center">
<HStack verticalAlignment="center">
<SocialButton icon="reply" />
<Text>{$item.replies_count}</Text>
</HStack>
<HStack verticalAlignment="center">
<SocialButton icon="trending-up" />
<Text>{$item.reblogs_count}</Text>
</HStack>
<HStack verticalAlignment="center">
<SocialButton
icon='like'
themeColor="{$item.favourited ? 'attention' : 'secondary'}"
onClick="() => {
if ($item.favourited) {
unfavoritePost.execute($item.id)
timelineData.refetch();
} else {
favoritePost.execute($item.id)
timelineData.refetch();
}
}
" />
<Text variant="caption">{$item.favourites_count}</Text>
</HStack>
</HStack>
</VStack>
</Card>
</Items>
</VStack>
</App>Key points
execute() returns a response from the backend: you can run code after the API call succeeds — such as refetching a DataSource, showing a toast, or navigating to another page.
refetch() re-issues the DataSource's request: Calling timelineData.refetch() re-sends the original query and updates every element bound to that DataSource when the fresh data arrives.
This pattern gives you surgical control: Unlike blanket cache invalidation (which refreshes every DataSource), ds.refetch() refreshes only the specific DataSource you choose.
Combine with invalidates="{[]}" to prevent double-fetching: By default a successful APICall invalidates all caches. If you manually refetch, set invalidates="{[]}" on the APICall to avoid a redundant second fetch.
See also
- Invalidate related data after a write — declarative cache control with the
invalidatesprop - Update UI optimistically — instant feedback before the server responds
- Retry a failed API call — handling failures and retrying