diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index c67001cc87..ebc4ce7ce8 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -263,8 +263,7 @@ export default class TextualBody extends React.Component { //console.info("shouldComponentUpdate: ShowUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview); // exploit that events are immutable :) - return (nextProps.mxEvent !== this.props.mxEvent || - nextProps.mxEvent.getId() !== this.props.mxEvent.getId() || + return (nextProps.mxEvent.getId() !== this.props.mxEvent.getId() || nextProps.highlights !== this.props.highlights || nextProps.replacingEventId !== this.props.replacingEventId || nextProps.highlightLink !== this.props.highlightLink || diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 90b620a239..15cedf81e7 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -300,9 +300,6 @@ interface IState { // The Relations model from the JS SDK for reactions to `mxEvent` reactions: Relations; - // Our snapshotted/local copy of the props.mxEvent, for local echo reasons - mxEvent: MatrixEvent; - hover: boolean; } @@ -337,8 +334,6 @@ export default class EventTile extends React.Component { // The Relations model from the JS SDK for reactions to `mxEvent` reactions: this.getReactions(), - mxEvent: this.mxEvent.toSnapshot(), // snapshot up front to verify it all works - hover: false, }; @@ -355,10 +350,6 @@ export default class EventTile extends React.Component { this.ref = React.createRef(); } - private get mxEvent(): MatrixEvent { - return this.state?.mxEvent ?? this.props.mxEvent; - } - /** * When true, the tile qualifies for some sort of special read receipt. This could be a 'sending' * or 'sent' receipt, for example. @@ -367,16 +358,16 @@ export default class EventTile extends React.Component { private get isEligibleForSpecialReceipt() { // First, if there are other read receipts then just short-circuit this. if (this.props.readReceipts && this.props.readReceipts.length > 0) return false; - if (!this.mxEvent) return false; + if (!this.props.mxEvent) return false; // Sanity check (should never happen, but we shouldn't explode if it does) - const room = this.context.getRoom(this.mxEvent.getRoomId()); + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); if (!room) return false; // Quickly check to see if the event was sent by us. If it wasn't, it won't qualify for // special read receipts. const myUserId = MatrixClientPeg.get().getUserId(); - if (this.mxEvent.getSender() !== myUserId) return false; + if (this.props.mxEvent.getSender() !== myUserId) return false; // Finally, determine if the type is relevant to the user. This notably excludes state // events and pretty much anything that can't be sent by the composer as a message. For @@ -387,7 +378,7 @@ export default class EventTile extends React.Component { EventType.RoomMessage, EventType.RoomMessageEncrypted, ]; - if (!simpleSendableEvents.includes(this.mxEvent.getType() as EventType)) return false; + if (!simpleSendableEvents.includes(this.props.mxEvent.getType() as EventType)) return false; // Default case return true; @@ -429,7 +420,7 @@ export default class EventTile extends React.Component { // TODO: [REACT-WARNING] Move into constructor // eslint-disable-next-line camelcase UNSAFE_componentWillMount() { - this.verifyEvent(this.mxEvent); + this.verifyEvent(this.props.mxEvent); } componentDidMount() { @@ -459,21 +450,11 @@ export default class EventTile extends React.Component { } shouldComponentUpdate(nextProps, nextState) { - // If the echo changed meaningfully, update. - if (!this.state.mxEvent?.isEquivalentTo(nextProps.mxEvent)) { - return true; - } - if (objectHasDiff(this.state, nextState)) { return true; } - if (!this.propsEqual(this.props, nextProps)) { - return true; - } - - // Always assume there's no significant change. - return false; + return !this.propsEqual(this.props, nextProps); } componentWillUnmount() { @@ -494,18 +475,11 @@ export default class EventTile extends React.Component { this.context.on("Room.receipt", this.onRoomReceipt); this.isListeningForReceipts = true; } - - // Update the state again if the snapshot needs updating. Note that this will fire - // a second state update to re-render child components, which ultimately calls didUpdate - // again, so we break that loop with a reference check first (faster than comparing events). - if (this.state.mxEvent === prevState.mxEvent && !this.state?.mxEvent.isEquivalentTo(this.props.mxEvent)) { - this.setState({mxEvent: this.props.mxEvent.toSnapshot()}); - } } private onRoomReceipt = (ev, room) => { // ignore events for other rooms - const tileRoom = MatrixClientPeg.get().getRoom(this.mxEvent.getRoomId()); + const tileRoom = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); if (room !== tileRoom) return; if (!this.shouldShowSentReceipt && !this.shouldShowSendingReceipt && !this.isListeningForReceipts) { @@ -529,19 +503,19 @@ export default class EventTile extends React.Component { // we need to re-verify the sending device. // (we call onHeightChanged in verifyEvent to handle the case where decryption // has caused a change in size of the event tile) - this.verifyEvent(this.mxEvent); + this.verifyEvent(this.props.mxEvent); this.forceUpdate(); }; private onDeviceVerificationChanged = (userId, device) => { - if (userId === this.mxEvent.getSender()) { - this.verifyEvent(this.mxEvent); + if (userId === this.props.mxEvent.getSender()) { + this.verifyEvent(this.props.mxEvent); } }; private onUserVerificationChanged = (userId, _trustStatus) => { - if (userId === this.mxEvent.getSender()) { - this.verifyEvent(this.mxEvent); + if (userId === this.props.mxEvent.getSender()) { + this.verifyEvent(this.props.mxEvent); } }; @@ -648,11 +622,11 @@ export default class EventTile extends React.Component { } shouldHighlight() { - const actions = this.context.getPushActionsForEvent(this.mxEvent.replacingEvent() || this.mxEvent); + const actions = this.context.getPushActionsForEvent(this.props.mxEvent.replacingEvent() || this.props.mxEvent); if (!actions || !actions.tweaks) { return false; } // don't show self-highlights from another of our clients - if (this.mxEvent.getSender() === this.context.credentials.userId) { + if (this.props.mxEvent.getSender() === this.context.credentials.userId) { return false; } @@ -667,7 +641,7 @@ export default class EventTile extends React.Component { getReadAvatars() { if (this.shouldShowSentReceipt || this.shouldShowSendingReceipt) { - return ; + return ; } // return early if there are no read receipts @@ -754,7 +728,7 @@ export default class EventTile extends React.Component { } onSenderProfileClick = event => { - const mxEvent = this.mxEvent; + const mxEvent = this.props.mxEvent; dis.dispatch({ action: Action.ComposerInsert, userId: mxEvent.getSender(), @@ -771,7 +745,7 @@ export default class EventTile extends React.Component { // Cancel any outgoing key request for this event and resend it. If a response // is received for the request with the required keys, the event could be // decrypted successfully. - this.context.cancelAndResendEventRoomKeyRequest(this.mxEvent); + this.context.cancelAndResendEventRoomKeyRequest(this.props.mxEvent); }; onPermalinkClicked = e => { @@ -780,14 +754,14 @@ export default class EventTile extends React.Component { e.preventDefault(); dis.dispatch({ action: 'view_room', - event_id: this.mxEvent.getId(), + event_id: this.props.mxEvent.getId(), highlighted: true, - room_id: this.mxEvent.getRoomId(), + room_id: this.props.mxEvent.getRoomId(), }); }; private renderE2EPadlock() { - const ev = this.mxEvent; + const ev = this.props.mxEvent; // event could not be decrypted if (ev.getContent().msgtype === 'm.bad.encrypted') { @@ -846,7 +820,7 @@ export default class EventTile extends React.Component { ) { return null; } - const eventId = this.mxEvent.getId(); + const eventId = this.props.mxEvent.getId(); return this.props.getRelationsForEvent(eventId, "m.annotation", "m.reaction"); }; @@ -865,13 +839,13 @@ export default class EventTile extends React.Component { const SenderProfile = sdk.getComponent('messages.SenderProfile'); const MemberAvatar = sdk.getComponent('avatars.MemberAvatar'); - //console.info("EventTile showUrlPreview for %s is %s", this.mxEvent.getId(), this.props.showUrlPreview); + //console.info("EventTile showUrlPreview for %s is %s", this.props.mxEvent.getId(), this.props.showUrlPreview); - const content = this.mxEvent.getContent(); + const content = this.props.mxEvent.getContent(); const msgtype = content.msgtype; - const eventType = this.mxEvent.getType(); + const eventType = this.props.mxEvent.getType(); - let tileHandler = getHandlerTile(this.mxEvent); + let tileHandler = getHandlerTile(this.props.mxEvent); // Info messages are basically information about commands processed on a room const isBubbleMessage = eventType.startsWith("m.key.verification") || @@ -888,7 +862,7 @@ export default class EventTile extends React.Component { // source tile when there's no regular tile for an event and also for // replace relations (which otherwise would display as a confusing // duplicate of the thing they are replacing). - if (SettingsStore.getValue("showHiddenEventsInTimeline") && !haveTileForEvent(this.mxEvent)) { + if (SettingsStore.getValue("showHiddenEventsInTimeline") && !haveTileForEvent(this.props.mxEvent)) { tileHandler = "messages.ViewSourceEvent"; // Reuse info message avatar and sender profile styling isInfoMessage = true; @@ -907,8 +881,8 @@ export default class EventTile extends React.Component { const EventTileType = sdk.getComponent(tileHandler); const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1); - const isRedacted = isMessageEvent(this.mxEvent) && this.props.isRedacted; - const isEncryptionFailure = this.mxEvent.isDecryptionFailure(); + const isRedacted = isMessageEvent(this.props.mxEvent) && this.props.isRedacted; + const isEncryptionFailure = this.props.mxEvent.isDecryptionFailure(); const isEditing = !!this.props.editState; const classes = classNames({ @@ -938,14 +912,14 @@ export default class EventTile extends React.Component { let permalink = "#"; if (this.props.permalinkCreator) { - permalink = this.props.permalinkCreator.forEvent(this.mxEvent.getId()); + permalink = this.props.permalinkCreator.forEvent(this.props.mxEvent.getId()); } // we can't use local echoes as scroll tokens, because their event IDs change. // Local echos have a send "status". - const scrollToken = this.mxEvent.status + const scrollToken = this.props.mxEvent.status ? undefined - : this.mxEvent.getId(); + : this.props.mxEvent.getId(); let avatar; let sender; @@ -975,15 +949,15 @@ export default class EventTile extends React.Component { needsSenderProfile = true; } - if (this.mxEvent.sender && avatarSize) { + if (this.props.mxEvent.sender && avatarSize) { let member; // set member to receiver (target) if it is a 3PID invite // so that the correct avatar is shown as the text is // `$target accepted the invitation for $email` - if (this.mxEvent.getContent().third_party_invite) { - member = this.mxEvent.target; + if (this.props.mxEvent.getContent().third_party_invite) { + member = this.props.mxEvent.target; } else { - member = this.mxEvent.sender; + member = this.props.mxEvent.sender; } avatar = (
@@ -998,17 +972,17 @@ export default class EventTile extends React.Component { if (needsSenderProfile) { if (!this.props.tileShape) { sender = ; } else { - sender = ; + sender = ; } } const MessageActionBar = sdk.getComponent('messages.MessageActionBar'); const actionBar = !isEditing ? { onFocusChange={this.onActionBarFocusChange} /> : undefined; - const showTimestamp = this.mxEvent.getTs() && + const showTimestamp = this.props.mxEvent.getTs() && (this.props.alwaysShowTimestamps || this.props.last || this.state.hover || this.state.actionBarFocused); const timestamp = showTimestamp ? - : null; + : null; const keyRequestHelpText =
@@ -1059,7 +1033,7 @@ export default class EventTile extends React.Component { if (!isRedacted) { const ReactionsRow = sdk.getComponent('messages.ReactionsRow'); reactionsRow = ; } @@ -1067,7 +1041,7 @@ export default class EventTile extends React.Component { const linkedTimestamp = { timestamp } ; @@ -1086,7 +1060,7 @@ export default class EventTile extends React.Component { switch (this.props.tileShape) { case 'notif': { - const room = this.context.getRoom(this.mxEvent.getRoomId()); + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); return React.createElement(this.props.as || "li", { "className": classes, "aria-live": ariaLive, @@ -1108,7 +1082,7 @@ export default class EventTile extends React.Component {
,
{ }, [
{ default: { const thread = ReplyThread.makeThread( - this.mxEvent, + this.props.mxEvent, this.props.onHeightChanged, this.props.permalinkCreator, this.replyThread, @@ -1178,7 +1152,7 @@ export default class EventTile extends React.Component { { groupPadlock } { thread }