fix: scrolling

This commit is contained in:
cha0s 2020-07-25 05:17:04 -05:00
parent d236f23b38
commit 22e6470ab8

View File

@ -1,6 +1,11 @@
import './chat--messages.scss'; import './chat--messages.scss';
import React, {useLayoutEffect, useRef} from 'react'; import React, {
useEffect,
useLayoutEffect,
useRef,
useState,
} from 'react';
import {useSelector} from 'react-redux'; import {useSelector} from 'react-redux';
import {channelMessagesSelector} from '~/common/state/chat'; import {channelMessagesSelector} from '~/common/state/chat';
@ -16,23 +21,35 @@ export default function ChatMessages() {
const channel = useChannel(); const channel = useChannel();
const $messages = useRef(null); const $messages = useRef(null);
const {current} = $messages; const {current} = $messages;
const isAtTheBottom = !current const [, setIsAtBottom] = useState(true);
? true const [outerHeight, setOuterHeight] = useState(0);
: 0 === current.scrollTop || ( const [scrollTop, setScrollTop] = useState(0);
current.scrollHeight const [scrollHeight, setScrollHeight] = useState(Infinity);
=== current.scrollTop
+ ['margin-top', 'margin-bottom'].reduce((r, property) => (
r + parseInt(window.getComputedStyle(current).getPropertyValue(property), 10)
), current.offsetHeight)
);
const heightWatch = current && current.scrollHeight;
const messages = useSelector((state) => channelMessagesSelector(state, channel)); const messages = useSelector((state) => channelMessagesSelector(state, channel));
const messageCount = messages && messages.length; const messageCount = messages && messages.length;
useEffect(() => {
const onResize = () => {
setOuterHeight(
!current
? 0
: ['margin-top', 'margin-bottom'].reduce((r, property) => (
r + parseInt(window.getComputedStyle(current).getPropertyValue(property), 10)
), current.offsetHeight),
);
setScrollHeight(!current ? 0 : current.scrollHeight);
};
window.addEventListener('resize', onResize);
onResize();
});
useLayoutEffect(() => { useLayoutEffect(() => {
if (isAtTheBottom) { const isAtBottom = !current
current?.scrollTo(0, !current ? 0 : current.scrollHeight); ? true
: 0 === scrollTop || scrollTop + outerHeight >= scrollHeight;
setIsAtBottom(isAtBottom);
if (isAtBottom) {
current?.scrollTo(0, scrollHeight);
} }
}, [current, heightWatch, messageCount, isAtTheBottom]); }, [current, messageCount, outerHeight, scrollHeight, scrollTop]);
if (!channel) { if (!channel) {
return null; return null;
} }
@ -42,6 +59,7 @@ export default function ChatMessages() {
<div className="chat--messagesSmoosh" /> <div className="chat--messagesSmoosh" />
<div <div
className="chat--messagesList" className="chat--messagesList"
onScroll={({target: {scrollTop}}) => setScrollTop(Math.round(scrollTop))}
ref={$messages} ref={$messages}
> >
{messages && messages.map((message) => { {messages && messages.map((message) => {