diff --git a/webroot/js/components/chat/chat-message-view.js b/webroot/js/components/chat/chat-message-view.js index 67c636240..df7c39f12 100644 --- a/webroot/js/components/chat/chat-message-view.js +++ b/webroot/js/components/chat/chat-message-view.js @@ -11,26 +11,39 @@ import { convertToText } from '../../utils/chat.js'; import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js'; export default class ChatMessageView extends Component { - async componentDidUpdate(prevProps) { - const { message, username } = this.props; - if (prevProps.message === message && this.state.formattedMessage) { - return; - } - const { body } = message; - - const formattedMessage = await formatMessageText(body, username); - this.setState({ - formattedMessage - }); - + constructor(props) { + super(props); + this.state = { + formattedMessage: '', + }; } + + shouldComponentUpdate(nextProps, nextState) { + const { formattedMessage } = this.state; + const { formattedMessage: nextFormattedMessage } = nextState; + + return (formattedMessage !== nextFormattedMessage); + } + + async componentDidMount() { + const { message, username } = this.props; + if (message && username) { + const { body } = message; + const formattedMessage = await formatMessageText(body, username); + this.setState({ + formattedMessage, + }); + } + } + + render() { const { message } = this.props; const { author, timestamp } = message; const { formattedMessage } = this.state; if (!formattedMessage) { - return; + return null; } const formattedTimestamp = formatTimestamp(timestamp); diff --git a/webroot/js/components/chat/chat.js b/webroot/js/components/chat/chat.js index f88f39849..eae3fc7cd 100644 --- a/webroot/js/components/chat/chat.js +++ b/webroot/js/components/chat/chat.js @@ -19,6 +19,7 @@ export default class Chat extends Component { webSocketConnected: true, messages: [], chatUserNames: [], + newMessagesReceived: false, }; this.scrollableMessagesContainer = createRef(); @@ -34,19 +35,37 @@ export default class Chat extends Component { this.submitChat = this.submitChat.bind(this); this.scrollToBottom = this.scrollToBottom.bind(this); this.handleWindowResize = debounce(this.handleWindowResize.bind(this), 500); - + this.handleNetworkingError = this.handleNetworkingError.bind(this); this.messageListCallback = this.messageListCallback.bind(this); } componentDidMount() { this.setupWebSocketCallbacks(); this.getChatHistory(); + window.addEventListener('resize', this.handleWindowResize); this.messageListObserver = new MutationObserver(this.messageListCallback); this.messageListObserver.observe(this.scrollableMessagesContainer.current, { childList: true }); } + shouldComponentUpdate(nextProps, nextState) { + const { username, chatInputEnabled } = this.props; + const { username: nextUserName, chatInputEnabled: nextChatEnabled } = nextProps; + + const { webSocketConnected, messages, chatUserNames, newMessagesReceived } = this.state; + const {webSocketConnected: nextSocket, messages: nextMessages, chatUserNames: nextUserNames, newMessagesReceived: nextMessagesReceived } = nextState; + + return ( + username !== nextUserName || + chatInputEnabled !== nextChatEnabled || + webSocketConnected !== nextSocket || + messages.length !== nextMessages.length || + chatUserNames.length !== nextUserNames.length || newMessagesReceived !== nextMessagesReceived + ); + } + + componentDidUpdate(prevProps, prevState) { const { username: prevName } = prevProps; const { username } = this.props; @@ -61,7 +80,9 @@ export default class Chat extends Component { // scroll to bottom of messages list when new ones come in if (messages.length > prevMessages.length) { - this.newMessagesReceived = true; + this.setState({ + newMessagesReceived: true, + }); } } componentWillUnmount() { @@ -96,7 +117,7 @@ export default class Chat extends Component { }); }) .catch(error => { - // this.handleNetworkingError(`Fetch getChatHistory: ${error}`); + this.handleNetworkingError(`Fetch getChatHistory: ${error}`); }); } @@ -113,6 +134,11 @@ export default class Chat extends Component { this.addMessage(message); } + handleNetworkingError(error) { + // todo: something more useful + console.log(error); + } + addMessage(message) { const { messages: curMessages } = this.state; @@ -196,14 +222,16 @@ export default class Chat extends Component { if (numMutations) { const item = mutations[numMutations - 1]; if (item.type === 'childList' && item.addedNodes.length) { - if (this.newMessagesReceived) { + if (this.state.newMessagesReceived) { if (!this.receivedFirstMessages) { this.scrollToBottom(); this.receivedFirstMessages = true; } else if (this.checkShouldScroll()) { this.scrollToBottom(); } - this.newMessagesReceived = false; + this.setState({ + newMessagesReceived: false, + }); } } } diff --git a/webroot/js/components/chat/message.js b/webroot/js/components/chat/message.js index b3028e5dc..cbd118a8b 100644 --- a/webroot/js/components/chat/message.js +++ b/webroot/js/components/chat/message.js @@ -1,34 +1,31 @@ -import { h, Component } from '/js/web_modules/preact.js'; +import { h } from '/js/web_modules/preact.js'; import htm from '/js/web_modules/htm.js'; const html = htm.bind(h); import ChatMessageView from './chat-message-view.js'; -import { messageBubbleColorForString } from '../../utils/user-colors.js'; import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js'; -export default class Message extends Component { - render(props) { - const { message } = props; - const { type } = message; - if (type === SOCKET_MESSAGE_TYPES.CHAT || type === SOCKET_MESSAGE_TYPES.SYSTEM) { - return html`<${ChatMessageView} ...${props} />`; - } else if (type === SOCKET_MESSAGE_TYPES.NAME_CHANGE) { - const { oldName, newName } = message; - return ( - html` -
-
-
- ${oldName} is now known as ${newName}. -
+export default function Message(props) { + const { message } = props; + const { type } = message; + if (type === SOCKET_MESSAGE_TYPES.CHAT || type === SOCKET_MESSAGE_TYPES.SYSTEM) { + return html`<${ChatMessageView} ...${props} />`; + } else if (type === SOCKET_MESSAGE_TYPES.NAME_CHANGE) { + const { oldName, newName } = message; + return ( + html` +
+
+
+ ${oldName} is now known as ${newName}.
- ` - ); - } else { - console.log("Unknown message type:", type); - } +
+ ` + ); + } else { + console.log("Unknown message type:", type); } }