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: "",
title: "",
content: ""
}
},
messagesLoadedIn: []
};
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': {
return {
...state,

View file

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

View file

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