I have a custom hook that freezes a passed text, once it changes to an empty string, for a set time to avoid the UI jumping during animations. Since I am accessing the text directly in track of useTask$, it is not a property access and thats why useTask$ is not triggered when the text changes.
// hooks/useFrozenText.ts
export function useFrozenText(text: string | undefined, delay: number) {
const frozenText = useSignal<string | undefined>();
useTask$(({ track }) => {
const nextText = track(() => text);
if (isBrowser && !nextText) {
setTimeout(() => (frozenText.value = nextText), delay);
} else {
frozenText.value = nextText;
}
});
return frozenText;
}
// components/Response.tsx
type ResponseProps = Partial<{
status: 'info' | 'error' | 'success';
message: string;
}>;
export const Response = component$(({ status, message }: ResponseProps) => {
// Freeze message while element collapses to prevent UI from jumping
const frozenMessage = useFrozenText(message, 200);
return (
<Expandable expanded={!!message}>
{frozenMessage.value}
</Expandable>
);
});