Update UI optimistically
For immediate user feedback, use component variables to update UI state instantly, providing a responsive experience while the backend processes the request.
<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"
inProgressNotificationMessage="Favoriting post..."
completedNotificationMessage="Post favorited!" />
<APICall
id="unfavoritePost"
method="post"
url="/api/posts/{$param}/unfavorite"
inProgressNotificationMessage="Unfavoriting post..."
completedNotificationMessage="Post unfavorited!" />
<DataSource
id="timelineData"
url="/api/timeline"
method="GET" />
<VStack gap="$space-4" padding="$space-4">
<Items data="{timelineData}">
<Card var.localFavorited="{null}" var.localFavoritesCount="{null}">
<VStack>
<Text>{$item.author}</Text>
<Text>{$item.content}</Text>
<HStack gap="$space-4" verticalAlignment="center">
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton icon="reply" />
<Text variant="caption">{$item.replies_count}</Text>
</HStack>
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton icon="trending-up" />
<Text variant="caption">{$item.reblogs_count}</Text>
</HStack>
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton
icon="like"
themeColor="{(localFavorited !== null ? localFavorited : $item.favourited) ? 'attention' : 'secondary'}">
<event name="click">
// Get current state (local takes precedence)
const currentFavorited = localFavorited !== null ? localFavorited : $item.favourited;
const currentCount = localFavoritesCount !== null ? localFavoritesCount : ($item.favourites_count || 0);
// Update UI optimistically
localFavorited = !currentFavorited;
localFavoritesCount = currentFavorited ?
Math.max(0, currentCount - 1) :
currentCount + 1;
// Make API call
if (currentFavorited) {
unfavoritePost.execute($item.id).then(() => timelineData.refetch());
} else {
favoritePost.execute($item.id).then(() => timelineData.refetch());
}
</event>
</SocialButton>
<Text variant="caption">
{localFavoritesCount !== null ? localFavoritesCount : ($item.favourites_count || 0)}
</Text>
</HStack>
</HStack>
</VStack>
</Card>
</Items>
</VStack>
</App>
Click the Like button - immediate feedback
<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"
inProgressNotificationMessage="Favoriting post..."
completedNotificationMessage="Post favorited!" />
<APICall
id="unfavoritePost"
method="post"
url="/api/posts/{$param}/unfavorite"
inProgressNotificationMessage="Unfavoriting post..."
completedNotificationMessage="Post unfavorited!" />
<DataSource
id="timelineData"
url="/api/timeline"
method="GET" />
<VStack gap="$space-4" padding="$space-4">
<Items data="{timelineData}">
<Card var.localFavorited="{null}" var.localFavoritesCount="{null}">
<VStack>
<Text>{$item.author}</Text>
<Text>{$item.content}</Text>
<HStack gap="$space-4" verticalAlignment="center">
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton icon="reply" />
<Text variant="caption">{$item.replies_count}</Text>
</HStack>
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton icon="trending-up" />
<Text variant="caption">{$item.reblogs_count}</Text>
</HStack>
<HStack gap="$space-1" verticalAlignment="center">
<SocialButton
icon="like"
themeColor="{(localFavorited !== null ? localFavorited : $item.favourited) ? 'attention' : 'secondary'}">
<event name="click">
// Get current state (local takes precedence)
const currentFavorited = localFavorited !== null ? localFavorited : $item.favourited;
const currentCount = localFavoritesCount !== null ? localFavoritesCount : ($item.favourites_count || 0);
// Update UI optimistically
localFavorited = !currentFavorited;
localFavoritesCount = currentFavorited ?
Math.max(0, currentCount - 1) :
currentCount + 1;
// Make API call
if (currentFavorited) {
unfavoritePost.execute($item.id).then(() => timelineData.refetch());
} else {
favoritePost.execute($item.id).then(() => timelineData.refetch());
}
</event>
</SocialButton>
<Text variant="caption">
{localFavoritesCount !== null ? localFavoritesCount : ($item.favourites_count || 0)}
</Text>
</HStack>
</HStack>
</VStack>
</Card>
</Items>
</VStack>
</App>