mirror of https://github.com/vector-im/riot-web
Merge pull request #205 from matrix-org/rav/shouldComponentUpdates_2
Re-introduce shouldComponentUpdate methods in RoomView and TimelinePanelpull/21833/head
commit
ec2e27a754
|
@ -77,3 +77,34 @@ module.exports.getKeyValueArrayDiffs = function(before, after) {
|
|||
|
||||
return results;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shallow-compare two objects for equality: each key and value must be
|
||||
* identical
|
||||
*/
|
||||
module.exports.shallowEqual = function(objA, objB) {
|
||||
if (objA === objB) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof objA !== 'object' || objA === null ||
|
||||
typeof objB !== 'object' || objB === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var keysA = Object.keys(objA);
|
||||
var keysB = Object.keys(objB);
|
||||
|
||||
if (keysA.length !== keysB.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < keysA.length; i++) {
|
||||
var key = keysA[i];
|
||||
if (!objB.hasOwnProperty(key) || objA[key] !== objB[key]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
|
|
@ -38,6 +38,7 @@ var SlashCommands = require("../../SlashCommands");
|
|||
var dis = require("../../dispatcher");
|
||||
var Tinter = require("../../Tinter");
|
||||
var rate_limited_func = require('../../ratelimitedfunc');
|
||||
var ObjectUtils = require('../../ObjectUtils');
|
||||
|
||||
var DEBUG = false;
|
||||
|
||||
|
@ -164,6 +165,11 @@ module.exports = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
|
||||
!ObjectUtils.shallowEqual(this.state, nextState));
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
// set a boolean to say we've been unmounted, which any pending
|
||||
// promises can use to throw away their results.
|
||||
|
@ -985,10 +991,10 @@ module.exports = React.createClass({
|
|||
// but it's better than the video going missing entirely
|
||||
if (auxPanelMaxHeight < 50) auxPanelMaxHeight = 50;
|
||||
|
||||
// we may need to resize the gemini panel after changing the aux panel
|
||||
// size, so add a callback to onChildResize.
|
||||
this.setState({auxPanelMaxHeight: auxPanelMaxHeight},
|
||||
this.onChildResize);
|
||||
this.setState({auxPanelMaxHeight: auxPanelMaxHeight});
|
||||
|
||||
// changing the maxHeight on the auxpanel will trigger a callback go
|
||||
// onChildResize, so no need to worry about that here.
|
||||
},
|
||||
|
||||
onFullscreenClick: function() {
|
||||
|
@ -1036,8 +1042,15 @@ module.exports = React.createClass({
|
|||
// XXX: this is a bit naughty; we should be doing this via props
|
||||
if (show) {
|
||||
this.setState({editingRoomSettings: true});
|
||||
var self = this;
|
||||
setTimeout(function() { self.onResize() }, 0);
|
||||
}
|
||||
},
|
||||
|
||||
// this has to be a proper method rather than an unnamed function,
|
||||
// otherwise react calls it with null on each update.
|
||||
_gatherTimelinePanelRef: function(r) {
|
||||
this.refs.messagePanel = r;
|
||||
if(r) {
|
||||
this.updateTint();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1200,7 +1213,7 @@ module.exports = React.createClass({
|
|||
draggingFile={this.state.draggingFile}
|
||||
displayConfCallNotification={this.state.displayConfCallNotification}
|
||||
maxHeight={this.state.auxPanelMaxHeight}
|
||||
onCallViewVideoRezize={this.onChildResize} >
|
||||
onResize={this.onChildResize} >
|
||||
{ aux }
|
||||
</AuxPanel>
|
||||
);
|
||||
|
@ -1279,12 +1292,7 @@ module.exports = React.createClass({
|
|||
}
|
||||
|
||||
var messagePanel = (
|
||||
<TimelinePanel ref={(r) => {
|
||||
this.refs.messagePanel = r;
|
||||
if(r) {
|
||||
this.updateTint();
|
||||
}
|
||||
}}
|
||||
<TimelinePanel ref={this._gatherTimelinePanelRef}
|
||||
room={this.state.room}
|
||||
hidden={hideMessagePanel}
|
||||
highlightedEventId={this.props.highlightedEventId}
|
||||
|
|
|
@ -24,6 +24,7 @@ var EventTimeline = Matrix.EventTimeline;
|
|||
var sdk = require('../../index');
|
||||
var MatrixClientPeg = require("../../MatrixClientPeg");
|
||||
var dis = require("../../dispatcher");
|
||||
var ObjectUtils = require('../../ObjectUtils');
|
||||
|
||||
var PAGINATE_SIZE = 20;
|
||||
var INITIAL_SIZE = 20;
|
||||
|
@ -119,6 +120,7 @@ var TimelinePanel = React.createClass({
|
|||
MatrixClientPeg.get().on("Room.timelineReset", this.onRoomTimelineReset);
|
||||
MatrixClientPeg.get().on("Room.redaction", this.onRoomRedaction);
|
||||
MatrixClientPeg.get().on("Room.receipt", this.onRoomReceipt);
|
||||
MatrixClientPeg.get().on("Room.localEchoUpdated", this.onLocalEchoUpdated);
|
||||
|
||||
this._initTimeline(this.props);
|
||||
},
|
||||
|
@ -146,6 +148,11 @@ var TimelinePanel = React.createClass({
|
|||
}
|
||||
},
|
||||
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
|
||||
!ObjectUtils.shallowEqual(this.state, nextState));
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
// set a boolean to say we've been unmounted, which any pending
|
||||
// promises can use to throw away their results.
|
||||
|
@ -161,6 +168,7 @@ var TimelinePanel = React.createClass({
|
|||
client.removeListener("Room.timelineReset", this.onRoomTimelineReset);
|
||||
client.removeListener("Room.redaction", this.onRoomRedaction);
|
||||
client.removeListener("Room.receipt", this.onRoomReceipt);
|
||||
client.removeListener("Room.localEchoUpdated", this.onLocalEchoUpdated);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -291,6 +299,21 @@ var TimelinePanel = React.createClass({
|
|||
this.forceUpdate();
|
||||
},
|
||||
|
||||
onLocalEchoUpdated: function(ev, room, oldEventId) {
|
||||
if (this.unmounted) return;
|
||||
|
||||
// ignore events for other rooms
|
||||
if (room !== this.props.room) return;
|
||||
|
||||
// Once the remote echo for an event arrives, we need to turn the
|
||||
// greyed-out event black. When the localEchoUpdated event is raised,
|
||||
// the nested 'event' property within one of the events in
|
||||
// _timelineWindow will have been replaced with the new event. So
|
||||
// all that is left to do here is to make the message-panel re-render.
|
||||
this.forceUpdate();
|
||||
},
|
||||
|
||||
|
||||
sendReadReceipt: function() {
|
||||
if (!this.refs.messagePanel) return;
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ var React = require('react');
|
|||
var MatrixClientPeg = require("../../../MatrixClientPeg");
|
||||
var sdk = require('../../../index');
|
||||
var dis = require("../../../dispatcher");
|
||||
var ObjectUtils = require('../../../ObjectUtils');
|
||||
|
||||
module.exports = React.createClass({
|
||||
displayName: 'AuxPanel',
|
||||
|
@ -39,9 +40,21 @@ module.exports = React.createClass({
|
|||
// therein
|
||||
maxHeight: React.PropTypes.number,
|
||||
|
||||
// a callback which is called when the video element in a voip call is
|
||||
// resized due to a change in video metadata
|
||||
onCallViewVideoResize: React.PropTypes.func,
|
||||
// a callback which is called when the content of the aux panel changes
|
||||
// content in a way that is likely to make it change size.
|
||||
onResize: React.PropTypes.func,
|
||||
},
|
||||
|
||||
shouldComponentUpdate: function(nextProps, nextState) {
|
||||
return (!ObjectUtils.shallowEqual(this.props, nextProps) ||
|
||||
!ObjectUtils.shallowEqual(this.state, nextState));
|
||||
},
|
||||
|
||||
componentDidUpdate: function(prevProps, prevState) {
|
||||
// most changes are likely to cause a resize
|
||||
if (this.props.onResize) {
|
||||
this.props.onResize();
|
||||
}
|
||||
},
|
||||
|
||||
onConferenceNotificationClick: function() {
|
||||
|
@ -87,7 +100,7 @@ module.exports = React.createClass({
|
|||
var callView = (
|
||||
<CallView ref="callView" room={this.props.room}
|
||||
ConferenceHandler={this.props.conferenceHandler}
|
||||
onResize={this.props.onCallViewVideoResize}
|
||||
onResize={this.props.onResize}
|
||||
maxVideoHeight={this.props.maxHeight}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -38,8 +38,8 @@ module.exports = React.createClass({
|
|||
// a callback which is called when the user clicks on the video div
|
||||
onClick: React.PropTypes.func,
|
||||
|
||||
// a callback which is called when the video within the callview is
|
||||
// resized due to a change in video metadata
|
||||
// a callback which is called when the content in the callview changes
|
||||
// in a way that is likely to cause a resize.
|
||||
onResize: React.PropTypes.func,
|
||||
},
|
||||
|
||||
|
@ -96,6 +96,10 @@ module.exports = React.createClass({
|
|||
this.getVideoView().getRemoteVideoElement().style.display = "none";
|
||||
dis.dispatch({action: 'video_fullscreen', fullscreen: false});
|
||||
}
|
||||
|
||||
if (this.props.onResize) {
|
||||
this.props.onResize();
|
||||
}
|
||||
},
|
||||
|
||||
getVideoView: function() {
|
||||
|
|
Loading…
Reference in New Issue