Reputation: 723
Some background, I'm attempting to create a message chat feed.
I have a NextUI ListBox
component that has the property isVirtualized
and the appropriate params. It is created using the following:
<>
<h1>{selectedServer ? selectedServer.serverAlias : "Chat Title"}</h1>
<ListboxWrapper ref={containerRef}>
<Listbox
isVirtualized
aria-label="Dynamic Actions"
items={chats}
selectedKeys={selectedKeys}
selectionMode="none"
onSelectionChange={setSelectedKeys}
virtualization={{
maxListboxHeight: 600,
itemHeight: 40,
}}
>
{(item) => (
<ListboxItem key={item.id}>
{item.text}
</ListboxItem>
)}
</Listbox>
</ListboxWrapper>
<Input
label="Send Message"
type={selectedServer ? "text" : "hidden"}
raduis={"full"}
onKeyUp={onKeyPressHandler}
value={textValue}
onChange={onChangeHandler}
/>
</>
And the ListboxWrapper
:
const ListboxWrapper = ({children}) => (
<div className="grid row-span-6 w-full h-full border-small px-1 py-2 rounded-small border-default-200 dark:border-default-100">
{children}
</div>
);
The items of the list are loaded dynamically. I would like the last item in the list to always be at the bottom of the containing div.
I currently have:
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({behavior: 'smooth' , block: 'end'})
}
Which scrolls to the top. It doesn't seem to matter what block I set (end
or start
), the behaviour is the same. Am I doing something wrong or is there an easier way to do this?
I had the same results with document.getElementById(..).scrollIntoView(..)
. I also moved the ref
to the last list item, but when I do that, the last list item appears at the top of the container and the other items are not visible and cannot be scrolled.
Thanks in advanced!
UPDATE:
I tried the solution suggested below but same behaviour.
It seems whenever I type text into the input box, the ListBox
scrolls to the top. I have updated the code above to include the full return
of the component.
The onKeyPressHandler
and onChangeHandler
functions with their hooks:
const [selectedKeys, setSelectedKeys] = React.useState(new Set(["text"]));
const selectedValue = React.useMemo(() => Array.from(selectedKeys).join(", "), [selectedKeys]);
const onKeyPressHandler = e => {
if (e.key === "Enter") {
const message = new ApiCall()
const chatRequest = new ChatRequest()
chatRequest.setChattext(textValue)
chatRequest.setServerid(selectedServer.serverID)
message.setChatrequest(chatRequest)
const apiCall = message.serializeBinary()
const requestOptions = {
method: 'POST',
headers: {'Content-Type': 'application/x-protobuf'},
body: apiCall
};
console.log("fetching chats")
fetch('http://localhost:8080/api/chats', requestOptions)
.then(response => {
if (response.ok) {
getChats()
}
changeTextValue("");
})
}
};
const onChangeHandler = e => {
changeTextValue(e.target.value);
};
And finally, the getChats
function, that gets the chats from the backend and calls scrollToBottom
when its complete:
const getChats = () => {
fetch("http://localhost:8080/api/chats?serverID=" + selectedServer.serverID)
.then(res => res.json())
.then(data => {
setChats(data);
scrollToBottom()
})
}
UPDATE2:
I added a console.log
to the scrollToBottom
function and it is only being called when the chats are updated. However, it isn't scrolling. Every time I type anything into the input box, the list scrolls to the top, almost like it is being redrawn?
UPDATE3:
I went back to the drawing board and did some research into grid and flex layouts. I have also switched from using the virtualised scroll that comes with ListBox
to css scrolling using overflow
, making the answer below work.
Upvotes: 1
Views: 67