Merge pull request #1801 from matrix-org/luke/perf-room-list
Improve room list performance when receiving messages
This commit is contained in:
commit
0d7099fd61
4 changed files with 78 additions and 22 deletions
|
@ -624,6 +624,7 @@ var TimelinePanel = React.createClass({
|
||||||
this.props.timelineSet.room.setUnreadNotificationCount('highlight', 0);
|
this.props.timelineSet.room.setUnreadNotificationCount('highlight', 0);
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'on_room_read',
|
action: 'on_room_read',
|
||||||
|
roomId: this.props.timelineSet.room.roomId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,12 +48,33 @@ module.exports = React.createClass({
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
componentWillMount: function() {
|
||||||
|
MatrixClientPeg.get().on("RoomState.events", this.onRoomStateEvents);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount: function() {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
if (cli) {
|
||||||
|
cli.removeListener("RoomState.events", this.onRoomStateEvents);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
componentWillReceiveProps: function(newProps) {
|
componentWillReceiveProps: function(newProps) {
|
||||||
this.setState({
|
this.setState({
|
||||||
urls: this.getImageUrls(newProps),
|
urls: this.getImageUrls(newProps),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoomStateEvents: function(ev) {
|
||||||
|
if (ev.getRoomId() !== this.props.room.roomId ||
|
||||||
|
ev.getType() !== 'm.room.avatar'
|
||||||
|
) return;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
urls: this.getImageUrls(this.props),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
getImageUrls: function(props) {
|
getImageUrls: function(props) {
|
||||||
return [
|
return [
|
||||||
ContentRepo.getHttpUriForMxc(
|
ContentRepo.getHttpUriForMxc(
|
||||||
|
|
|
@ -77,9 +77,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
cli.on("Room", this.onRoom);
|
cli.on("Room", this.onRoom);
|
||||||
cli.on("deleteRoom", this.onDeleteRoom);
|
cli.on("deleteRoom", this.onDeleteRoom);
|
||||||
cli.on("Room.name", this.onRoomName);
|
|
||||||
cli.on("Room.receipt", this.onRoomReceipt);
|
cli.on("Room.receipt", this.onRoomReceipt);
|
||||||
cli.on("RoomState.events", this.onRoomStateEvents);
|
|
||||||
cli.on("RoomMember.name", this.onRoomMemberName);
|
cli.on("RoomMember.name", this.onRoomMemberName);
|
||||||
cli.on("Event.decrypted", this.onEventDecrypted);
|
cli.on("Event.decrypted", this.onEventDecrypted);
|
||||||
cli.on("accountData", this.onAccountData);
|
cli.on("accountData", this.onAccountData);
|
||||||
|
@ -161,12 +159,6 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'on_room_read':
|
|
||||||
// Force an update because the notif count state is too deep to cause
|
|
||||||
// an update. This forces the local echo of reading notifs to be
|
|
||||||
// reflected by the RoomTiles.
|
|
||||||
this.forceUpdate();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -177,9 +169,7 @@ module.exports = React.createClass({
|
||||||
if (MatrixClientPeg.get()) {
|
if (MatrixClientPeg.get()) {
|
||||||
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
MatrixClientPeg.get().removeListener("Room", this.onRoom);
|
||||||
MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom);
|
MatrixClientPeg.get().removeListener("deleteRoom", this.onDeleteRoom);
|
||||||
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
|
||||||
MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
|
MatrixClientPeg.get().removeListener("Room.receipt", this.onRoomReceipt);
|
||||||
MatrixClientPeg.get().removeListener("RoomState.events", this.onRoomStateEvents);
|
|
||||||
MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName);
|
MatrixClientPeg.get().removeListener("RoomMember.name", this.onRoomMemberName);
|
||||||
MatrixClientPeg.get().removeListener("Event.decrypted", this.onEventDecrypted);
|
MatrixClientPeg.get().removeListener("Event.decrypted", this.onEventDecrypted);
|
||||||
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
||||||
|
@ -243,14 +233,6 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onRoomName: function(room) {
|
|
||||||
this._delayedRefreshRoomList();
|
|
||||||
},
|
|
||||||
|
|
||||||
onRoomStateEvents: function(ev, state) {
|
|
||||||
this._delayedRefreshRoomList();
|
|
||||||
},
|
|
||||||
|
|
||||||
onRoomMemberName: function(ev, member) {
|
onRoomMemberName: function(ev, member) {
|
||||||
this._delayedRefreshRoomList();
|
this._delayedRefreshRoomList();
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,6 +21,7 @@ const React = require('react');
|
||||||
const ReactDOM = require("react-dom");
|
const ReactDOM = require("react-dom");
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
const classNames = require('classnames');
|
const classNames = require('classnames');
|
||||||
|
import dis from '../../../dispatcher';
|
||||||
const MatrixClientPeg = require('../../../MatrixClientPeg');
|
const MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||||
import DMRoomMap from '../../../utils/DMRoomMap';
|
import DMRoomMap from '../../../utils/DMRoomMap';
|
||||||
const sdk = require('../../../index');
|
const sdk = require('../../../index');
|
||||||
|
@ -58,7 +59,9 @@ module.exports = React.createClass({
|
||||||
hover: false,
|
hover: false,
|
||||||
badgeHover: false,
|
badgeHover: false,
|
||||||
menuDisplayed: false,
|
menuDisplayed: false,
|
||||||
|
roomName: this.props.room.name,
|
||||||
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
notifState: RoomNotifs.getRoomNotifsState(this.props.room.roomId),
|
||||||
|
notificationCount: this.props.room.getUnreadNotificationCount(),
|
||||||
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
|
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -81,6 +84,20 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onRoomTimeline: function(ev, room) {
|
||||||
|
if (room !== this.props.room) return;
|
||||||
|
this.setState({
|
||||||
|
notificationCount: this.props.room.getUnreadNotificationCount(),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onRoomName: function(room) {
|
||||||
|
if (room !== this.props.room) return;
|
||||||
|
this.setState({
|
||||||
|
roomName: this.props.room.name,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
onAccountData: function(accountDataEvent) {
|
onAccountData: function(accountDataEvent) {
|
||||||
if (accountDataEvent.getType() == 'm.push_rules') {
|
if (accountDataEvent.getType() == 'm.push_rules') {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -89,6 +106,21 @@ module.exports = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onAction: function(payload) {
|
||||||
|
switch (payload.action) {
|
||||||
|
// XXX: slight hack in order to zero the notification count when a room
|
||||||
|
// is read. Ideally this state would be given to this via props (as we
|
||||||
|
// do with `unread`). This is still better than forceUpdating the entire
|
||||||
|
// RoomList when a room is read.
|
||||||
|
case 'on_room_read':
|
||||||
|
if (payload.roomId !== this.props.room.roomId) break;
|
||||||
|
this.setState({
|
||||||
|
notificationCount: this.props.room.getUnreadNotificationCount(),
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_onActiveRoomChange: function() {
|
_onActiveRoomChange: function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
|
selected: this.props.room.roomId === RoomViewStore.getRoomId(),
|
||||||
|
@ -97,15 +129,37 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
componentWillMount: function() {
|
componentWillMount: function() {
|
||||||
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
MatrixClientPeg.get().on("accountData", this.onAccountData);
|
||||||
|
MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
|
||||||
|
MatrixClientPeg.get().on("Room.name", this.onRoomName);
|
||||||
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
|
ActiveRoomObserver.addListener(this.props.room.roomId, this._onActiveRoomChange);
|
||||||
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
},
|
},
|
||||||
|
|
||||||
componentWillUnmount: function() {
|
componentWillUnmount: function() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
if (cli) {
|
if (cli) {
|
||||||
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
MatrixClientPeg.get().removeListener("accountData", this.onAccountData);
|
||||||
|
MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
|
||||||
|
MatrixClientPeg.get().removeListener("Room.name", this.onRoomName);
|
||||||
}
|
}
|
||||||
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
|
ActiveRoomObserver.removeListener(this.props.room.roomId, this._onActiveRoomChange);
|
||||||
|
dis.unregister(this.dispatcherRef);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Do a simple shallow comparison of props and state to avoid unnecessary
|
||||||
|
// renders. The assumption made here is that only state and props are used
|
||||||
|
// in rendering this component and children.
|
||||||
|
//
|
||||||
|
// RoomList is frequently made to forceUpdate, so this decreases number of
|
||||||
|
// RoomTile renderings.
|
||||||
|
shouldComponentUpdate: function(newProps, newState) {
|
||||||
|
if (Object.keys(newProps).some((k) => newProps[k] !== this.props[k])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (Object.keys(newState).some((k) => newState[k] !== this.state[k])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
onClick: function(ev) {
|
onClick: function(ev) {
|
||||||
|
@ -174,7 +228,7 @@ module.exports = React.createClass({
|
||||||
const myUserId = MatrixClientPeg.get().credentials.userId;
|
const myUserId = MatrixClientPeg.get().credentials.userId;
|
||||||
const me = this.props.room.currentState.members[myUserId];
|
const me = this.props.room.currentState.members[myUserId];
|
||||||
|
|
||||||
const notificationCount = this.props.room.getUnreadNotificationCount();
|
const notificationCount = this.state.notificationCount;
|
||||||
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
// var highlightCount = this.props.room.getUnreadNotificationCount("highlight");
|
||||||
|
|
||||||
const notifBadges = notificationCount > 0 && this._shouldShowNotifBadge();
|
const notifBadges = notificationCount > 0 && this._shouldShowNotifBadge();
|
||||||
|
@ -202,9 +256,7 @@ module.exports = React.createClass({
|
||||||
'mx_RoomTile_badgeButton': this.state.badgeHover || this.state.menuDisplayed,
|
'mx_RoomTile_badgeButton': this.state.badgeHover || this.state.menuDisplayed,
|
||||||
});
|
});
|
||||||
|
|
||||||
// XXX: We should never display raw room IDs, but sometimes the
|
let name = this.state.roomName;
|
||||||
// room name js sdk gives is undefined (cannot repro this -- k)
|
|
||||||
let name = this.props.room.name || this.props.room.roomId;
|
|
||||||
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
|
name = name.replace(":", ":\u200b"); // add a zero-width space to allow linewrapping after the colon
|
||||||
|
|
||||||
let badge;
|
let badge;
|
||||||
|
|
Loading…
Reference in a new issue