如何在React聊天页面中向上滚动历史记录



*尝试显示类似于Skype或任何流行聊天应用程序的无限重载聊天历史

在聊天页面中。如果我的聊天信息限制为10条。

聊天有30个。

当我加载聊天时,它将显示最新的10。

当我滚动到顶部时,我想看到前10个。

我自己尝试过,滚动位置保持不变,但消息加载在视图中。

它应该加载到顶部并保持滚动位置。

如何做到这一点?

这是我的页面:https://pastebin.com/36xZPG1W

import React, { useRef, useState, useEffect } from 'react';
import produce from 'immer';
import dayjs from 'dayjs';
import { WithT } from 'i18next';

import * as ErrorHandler from 'components/ErrorHandler';
import useOnScreen from 'utils/useOnScreen';

import getLang from 'utils/getLang';

import Message from './Message';
const limit = 10;
const lang = getLang();
interface IMessagesProps extends WithT {
messages: any;
currentUserID: string;
chatID: string;
fetchMore: any;
typingText: any;
setSelectedMsg: any;
removeMessage: any;
}

const Messages: React.FC<IMessagesProps> = ({
messages,
currentUserID,
chatID,
fetchMore,
setSelectedMsg,
removeMessage,
t,
}) => {
const elementRef = useRef(null);
const isOnScreen = useOnScreen(elementRef);
const topElementRef = useRef(null);
const topIsOnScreen = useOnScreen(topElementRef);

const isUserInside = useRef(true);
const scroller = useRef<HTMLDivElement>(null);
const messagesEnd = useRef<HTMLDivElement>(null);
const [hasMore, setHasMore] = useState(true);

useEffect(() => {
scrollToBottom();
}, []);

useEffect(() => {
autoscroll();
}, [messages]);

//NOT WORKING
const autoscroll = () => {
// Visible height
const visibleHeight = scroller.current.offsetHeight;

// Height of messages container
const containerHeight = scroller.current.scrollHeight;

// How far have I scrolled?
const scrollOffset = scroller.current.scrollTop + visibleHeight;
// New message element
const firstChild = scroller.current.firstElementChild;
console.log(`visibleHeight`, visibleHeight);
console.log(`containerHeight`, containerHeight);
console.log(`scrollOffset`, scrollOffset);
console.log(`firstChild`, firstChild.offsetHeight);
console.log(`firstChild`, firstChild.scrollHeight);
console.log(`firstChild`, firstChild);
scroller.current.scrollTop = scrollOffset;
// // Height of the new message
// const newMessageStyles = getComputedStyle($newMessage)
// const newMessageMargin = parseInt(newMessageStyles.marginBottom)
// const newMessageHeight = $newMessage.offsetHeight + newMessageMargin

// // Visible height
// const visibleHeight = $messages.offsetHeight

// // Height of messages container
// const containerHeight = $messages.scrollHeight

// // How far have I scrolled?
// const scrollOffset = $messages.scrollTop + visibleHeight

// if (containerHeight - newMessageHeight <= scrollOffset) {
//     $messages.scrollTop = $messages.scrollHeight
// }
};

const fetchDataForScrollUp = cursor => {
ErrorHandler.setBreadcrumb('fetch more messages');
if (!hasMore) {
return;
}
fetchMore({
variables: {
chatID,
limit,
cursor,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
if (!fetchMoreResult?.getMessages || fetchMoreResult.getMessages.messages.length < limit) {
setHasMore(false);
return previousResult;
}
const newData = produce(previousResult, draftState => {
draftState.getMessages.messages = [...previousResult.getMessages.messages, ...fetchMoreResult.getMessages.messages];
});

return newData;
},
});
};

if (messages?.length >= limit) {
if (topIsOnScreen) {
fetchDataForScrollUp(messages[messages.length - 1].id);
}
}

if (isOnScreen) {
isUserInside.current = true;
} else {
isUserInside.current = false;
}

const scrollToBottom = () => {
if (messagesEnd.current) {
messagesEnd.current.scrollIntoView({ behavior: 'smooth' });
}
};

const groupBy = function (arr, criteria) {
return arr.reduce(function (obj, item) {
// Check if the criteria is a function to run on the item or a property of it
const key = typeof criteria === 'function' ? criteria(item) : item[criteria];

// If the key doesn't exist yet, create it
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
obj[key] = [];
}

// Push the value to the object
obj[key].push(item);

// Return the object to the next item in the loop
return obj;
}, {});
};

const objectMap = object => {
return Object.keys(object).reduce(function (result, key) {
result.push({ date: key, messages: object[key] });
return result;
}, []);
};

const group = groupBy(messages, datum => dayjs(datum.createdAt).locale(lang).format('dddd, MMMM D, YYYY').toLocaleUpperCase());
const messageElements = objectMap(group)
.reverse()
.map((item, index) => {
const messageElements = item.messages
.map(message => {
return (
<Message
key={uniqueKey}
message={message}
currentUserID={currentUserID}
lang={lang}
removeMessage={removeMessage}
t={t}
chatID={chatID}
setSelectedMsg={setSelectedMsg}
/>
);
})
.reverse();

return messageElements;
})
.reduce((a, b) => a.concat(b), []);

return (
<div style={{ marginBottom: '25px' }}>
<div ref={topElementRef} />
<div
style={{
position: 'relative',
display: 'flex',
flexDirection: 'column',
flexWrap: 'wrap',
height: '100%',
overflow: 'hidden',
}}
ref={scroller}
>
{messageElements}
<div ref={elementRef} style={{ position: 'absolute', bottom: '5%' }} />
</div>
</div>
);
};

export default Messages;

我已经坚持了两个星期了,哈哈。任何建议都有帮助:(

您尝试过scrollIntoView吗?您可以在更改autoscroll功能后尝试,如以下

const autoscroll = () => {
elementRef.current.scrollIntoView({ behavior: 'smooth' })
};

相关内容

  • 没有找到相关文章

最新更新