I'm creating a websocket based chat app to experiment with Fresh, but I'm struggling to render a basic list of messages to the page. Here's some code:
routes/chat.tsx
export default function Chat() {
return (
<div>
// ...
<MyIsland username={username.value}></MyIsland>
</div>
)
}
islands/MyIsland.tsx
export default function MyIsland(props: IslandProps) {
const ws = useSignal<WebSocket | null>(null);
const messageList = useSignal<Message[]>([]);
useEffect(() => {
if (props.username) {
ws.value = new WebSocket("ws://localhost:5000?username=" + props.username);
ws.value.onopen = () => { console.log('Connected..') }
ws.value.onmessage = updateMessages;
}
}, []);
const updateMessages = useCallback((m: MessageEvent<string>) => {
const data: WsData = JSON.parse(m.data);
if (data.type == SocketMessageType.Text){
const message: Message = data.value;
messageList.value.push(message);
}
}, [])
const send = useCallback((text: string) => {
if (ws.value) {
const data = // ...
ws.value.send(JSON.stringify(data));
}
}, [ws]);
return (
<div>
<Button onClick={() => send('test')}>Send</Button>
<div>
{messageList.value.map((m) => ( <MessageItem {...m} /> ))} // problem here
</div>
</div>
)
}
I would expect the messageList.value.map
at the bottom of MyIsland
to be updated on the page as the list fills with messages, but this is not the case. I have verified that the list is being updated correctly in the background, it's just the html that is not updated. I'm very new to fresh and server+client rendered frameworks in general so I suspect I might be misunderstanding the way the islands are rendered. Thanks for any help!
Your state isn't getting updated because your array reference doesn't change. You need to assign a new array to messageList.value
in order to make it update the state.
Instead of
messageList.value.push(message);
do
messageList.value = [...messageList.value, message];
And it will work as you expect it.