Mailspring/internal_packages/notifications/lib/sidebar/sync-activity.jsx
Mark Hahnenberg aa384567f0 [perf] Fix CSS animation for ellipses in "Syncing your mailbox"
Summary:
This animation was changing the width of the after pseudoelement, which was
causing a lot of repainting and layout to occur in the very bottom corner of
the screen. This in turn caused an idle window to use 50-70% CPU all the
time during initial sync. The fix is to change the after element to three
spans and modify the animation to alter their opacity which avoids having to
do style and layout reflows due to width changes. It also looks slightly cooler
IMHO :-) An idle main window now sits around 8% CPU on my laptop.

Test Plan: Run locally, verify that CPU is lower.

Reviewers: evan, juan

Reviewed By: juan

Subscribers: halla

Differential Revision: https://phab.nylas.com/D3810
2017-01-30 13:43:12 -08:00

100 lines
2.3 KiB
JavaScript

import classNames from 'classnames';
import {Actions, React, Utils} from 'nylas-exports';
import InitialSyncActivity from './initial-sync-activity';
import SyncbackActivity from './syncback-activity';
export default class SyncActivity extends React.Component {
static propTypes = {
initialSync: React.PropTypes.bool,
syncbackTasks: React.PropTypes.array,
}
constructor() {
super()
this.state = {
expanded: false,
blink: false,
}
this.mounted = false;
}
componentDidMount() {
this.mounted = true;
this.unsub = Actions.expandInitialSyncState.listen(this.showExpandedState);
}
shouldComponentUpdate(nextProps, nextState) {
return !Utils.isEqualReact(nextProps, this.props) ||
!Utils.isEqualReact(nextState, this.state);
}
componentWillUnmount() {
this.mounted = false;
this.unsub();
}
showExpandedState = () => {
if (!this.state.expanded) {
this.setState({expanded: true});
} else {
this.setState({blink: true});
setTimeout(() => {
if (this.mounted) {
this.setState({blink: false});
}
}, 1000)
}
}
hideExpandedState = () => {
this.setState({expanded: false});
}
_renderInitialSync() {
if (!this.props.initialSync) { return false; }
return <InitialSyncActivity />
}
_renderSyncbackTasks() {
return <SyncbackActivity syncbackTasks={this.props.syncbackTasks} />
}
_renderExpandedDetails() {
return (
<div>
<a className="close-expanded" onClick={this.hideExpandedState}>Hide</a>
{this._renderSyncbackTasks()}
{this._renderInitialSync()}
</div>
)
}
render() {
const {initialSync, syncbackTasks} = this.props;
if (!initialSync && (!syncbackTasks || syncbackTasks.length === 0)) {
return false;
}
const classSet = classNames({
'item': true,
'expanded-sync': this.state.expanded,
'blink': this.state.blink,
});
const ellipses = [1, 2, 3].map((i) => <span className={`ellipsis${i}`}>.</span>);
return (
<div
className={classSet}
key="sync-activity"
onClick={() => (this.setState({expanded: !this.state.expanded}))}
>
<div className="inner clickable">Syncing your mailbox{ellipses}</div>
{this.state.expanded ? this._renderExpandedDetails() : false}
</div>
)
}
}