50 lines
1.8 KiB
JavaScript
50 lines
1.8 KiB
JavaScript
import { useEffect, useState, useCallback, memo } from 'react';
|
|
import { SERVER_BASE_URL } from './App';
|
|
import { Message } from './Message';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export var MessageList = memo(function MessageList({ messages, setMessages, userSecret }) {
|
|
var [atBottom, setAtBottom] = useState(true);
|
|
var [atTop, setAtTop] = useState(false);
|
|
|
|
var onScroll = useCallback(event => {
|
|
var { scrollTop, scrollHeight, clientHeight } = event.target;
|
|
setAtBottom(scrollHeight - (scrollTop + clientHeight) < 32);
|
|
setAtTop(scrollTop < 32);
|
|
}, [setAtBottom, setAtTop]);
|
|
|
|
var loadOlderMessages = useCallback(async () => {
|
|
var olderMessages = await fetch(SERVER_BASE_URL + "/messages?secret=" + userSecret + "&before=" + messages[0].timestamp).then(res => res.json());
|
|
console.debug("loadOlderMessages", olderMessages);
|
|
setMessages(messages => [...olderMessages, ...messages]);
|
|
// why don't either of these work on ios (webkit) ?
|
|
//document.getElementById(messages[0]._id).scrollIntoView();
|
|
setTimeout(() => document.getElementById(olderMessages.at(-1)._id).scrollIntoView(), 0);
|
|
}, [setMessages, messages, userSecret]);
|
|
|
|
var scrollToBottom = () => document.getElementById(messages.at(-1)?._id)?.scrollIntoView();
|
|
useEffect(() => {
|
|
if (atBottom) scrollToBottom();
|
|
});
|
|
var observer = new ResizeObserver(() => atBottom && scrollToBottom());
|
|
|
|
useEffect(() => {
|
|
console.debug("atTop", atTop);
|
|
if (atTop) loadOlderMessages();
|
|
}, [atTop, loadOlderMessages]);
|
|
useEffect(() => {
|
|
console.debug("atBottom", atBottom);
|
|
if (atBottom) setMessages(messages => messages.slice(-100));
|
|
}, [atBottom, setMessages]);
|
|
|
|
|
|
|
|
return <ul className="py-4 w-full flex-1 overflow-auto break-words" onScroll={onScroll} onLoad={e => observer.observe(e.target)}>
|
|
{messages.map(message => <Message message={message} key={message._id} />)}
|
|
</ul>;
|
|
});
|