I am attempting to code a chat page for a ticketing system, where both client and employee messages show up on the page as they are submitted (i.e. without needing a page refresh). To do this, I've got a chats endpoint which returns all the messages as JSON.
I haven't found a qwik way to do this, so I'm using setInterval() on the page to poll the endpoint. The returned data is handled by <Resource /> and works BUT the message components are rebuilt every time, whether they've changed or not.
I've noticed that when the page is first built (on the server), the message components have keys, but when rebuilt they lose their keys. I can't see why this is the case.
useVisibleTask$() fires up setInterval() which periodically changes the updateSignal value, which in turn triggers chatResource to be re-called. That's how I get the resulting data into the <Resource />. All the chat bubbles are created, but their keys are lost, which I believe requires them to be recreated every time.
Given that the chat bubbles are created and that chat.id exists, I'd expect the components to have keys.
Given that this is a convoluted approach, I'd hope that there's a better way to go about the whole thing!
export default component$(() => {
const updateSignal = useSignal(0);
const chatResource = useResource$(async ({ track, cleanup }) => {
track(() => updateSignal.value);
const abortController = new AbortController();
cleanup(() => { abortController.abort("cleanup"); });
const res = await fetch("http://localhost:5173/api/chats/", { signal: abortController.signal });
const chats = await res.json() as Chat[];
return chats;
});
useVisibleTask$(() => {
setInterval(() => {
updateSignal.value = updateSignal.value + 1
}, 7500);
});
return (
<main>
<div id="chatMessages">
<Resource
value={chatResource}
onPending={() => <p>Loading...</p>}
onResolved={(chats: Chat[]) => {
return (<>
{
chats.map((chat) => {
return <ChatBubble chat={chat} key={chat.id} />
})
}
</>);
}}
/>
</div >
</main>
);
});
Here is a simplified project which demonstrates the problem (you'll have to inspect the DOM to see the setInterval() updates destroy the component keys).