improvement: optimize ChannelMessageView and prevent sending a request for initial messages multiple times (has issues; see TODO)

This commit is contained in:
hippoz 2021-10-23 01:34:46 +03:00
parent 3664b4e57b
commit 0090f5dc90
Signed by: hippoz
GPG key ID: 7C52899193467641
3 changed files with 77 additions and 34 deletions

View file

@ -13,7 +13,8 @@ const intitialState = {
glyph: "", glyph: "",
title: "", title: "",
content: "" content: ""
} },
messagesLoadedIn: []
}; };
const reducer = (state = intitialState, payload) => { const reducer = (state = intitialState, payload) => {
@ -74,6 +75,16 @@ const reducer = (state = intitialState, payload) => {
}; };
} }
case 'channels/firstmessageload': {
return {
...state,
messagesLoadedIn: [
...state.messagesLoadedIn,
payload.channelId
]
};
}
case 'channels/updatepresence': { case 'channels/updatepresence': {
return { return {
...state, ...state,

View file

@ -1,52 +1,83 @@
import { useRef, useEffect, useState } from 'react'; import { PureComponent, createRef } from 'react';
import { useDispatch } from "react-redux"; import { connect } from "react-redux";
import { authenticated } from "../../api/request"; import { authenticated } from "../../api/request";
import { getJsonValue } from '../../common/environmentmanager';
import Message from "../Message"; import Message from "../Message";
export default function ChannelMessageView({ messages, channelId }) { class ChannelMessageView extends PureComponent {
const invisibleBottomMessageRef = useRef(); constructor() {
super();
this.state = {
isLoading: false
};
this.invisibleBottomMessageRef = createRef();
this.scroller = createRef();
const [isLoading, setIsLoading] = useState(false); this.onScroll = this.onScroll.bind(this);
const dispatch = useDispatch(); }
const scroller = useRef();
const loadOlderMessages = () => { loadOlderMessages() {
if (isLoading) return; if (this.state.isLoading) return;
if (!channelId) return; if (!getJsonValue("loadMessages")) return; // parse as json to get boolean
setIsLoading(true); if (!this.props.channelId) return;
this.setState({ isLoading: true });
const request = messages[0] ? `/api/v1/content/channel/${channelId}/messages?before=${messages[0]._id}` : `/api/v1/content/channel/${channelId}/messages`; const request = this.props.messages[0] ? `/api/v1/content/channel/${this.props.channelId}/messages?before=${this.props.messages[0]._id}` : `/api/v1/content/channel/${this.props.channelId}/messages`;
authenticated(request) authenticated(request)
.then((res) => { .then((res) => {
if (res.json.channelMessages) if (res.json.channelMessages)
dispatch({ this.props.dispatch({
type: "messagestore/addmessagesback", type: "messagestore/addmessagesback",
messages: res.json.channelMessages.reverse(), messages: res.json.channelMessages.reverse(),
channelId channelId: this.props.channelId
}) });
}) })
.then(() => { .then(() => {
setIsLoading(false); this.setState({ isLoading: false });
}); });
};
const onScroll = () => {
if (scroller.current.scrollTop === 0) {
loadOlderMessages();
} }
};
// eslint-disable-next-line react-hooks/exhaustive-deps firstTimeMessageLoad() {
useEffect(loadOlderMessages, [channelId, dispatch]); if (!this.props.channelId) return false;
if (this.props.messagesLoadedIn.includes(this.props.channelId)) return false;
this.props.dispatch({
type: "channels/firstmessageload",
channelId: this.props.channelId
});
this.loadOlderMessages();
}
useEffect(() => { onScroll() {
invisibleBottomMessageRef.current.scrollIntoView(true); // TODO: this triggers when switching between channels so the firstmessageload check does not take effect
}, [messages]); if (this.scroller.current.scrollTop === 0)
this.loadOlderMessages();
}
return <div className="message-list" id="message-list" ref={ scroller } onScroll={ onScroll }> componentDidMount() {
{messages.map(message => <Message message={message} key={message._id} />)} this.firstTimeMessageLoad();
<div className="messages-scroll-div" ref={ invisibleBottomMessageRef }></div> }
componentDidUpdate(prevProps) {
if (prevProps.messages !== this.props.messages) {
this.invisibleBottomMessageRef.current.scrollIntoView(true);
}
if (prevProps.channelId !== this.props.channelId) {
this.firstTimeMessageLoad();
}
}
render() {
return <div className="message-list" id="message-list" ref={ this.scroller } onScroll={ this.onScroll }>
{this.props.messages.map(message => <Message message={message} key={message._id} />)}
<div className="messages-scroll-div" ref={ this.invisibleBottomMessageRef }></div>
</div>; </div>;
} }
}
export default connect((state) => {
return {
messagesLoadedIn: state.messagesLoadedIn
};
}, null)(ChannelMessageView);

View file

@ -1,7 +1,8 @@
const config = { const config = {
apiUrl: "http://localhost:3000", apiUrl: "http://localhost:3000",
gatewayUrl: "ws://localhost:3005/gateway", gatewayUrl: "ws://localhost:3005/gateway",
gatewayConnectionAttributes: ["PRESENCE_UPDATES"] gatewayConnectionAttributes: ["PRESENCE_UPDATES"],
loadMessages: true
}; };
export default config; export default config;