*尝试显示类似于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' })
};