From 10a241b60083aa4088de9e652561ee38ee53591a Mon Sep 17 00:00:00 2001 From: Gregory Schier Date: Wed, 9 Aug 2017 17:13:59 -0700 Subject: [PATCH] Refactor to minimize re-rendering of certain aspects --- app/sync/storage.js | 28 ++++++++++- app/ui/components/base/modal.js | 16 ++----- app/ui/components/codemirror/code-editor.js | 2 +- app/ui/components/dropdowns/sync-dropdown.js | 47 +++++++++---------- .../modals/request-switcher-modal.js | 42 ++++++++--------- app/ui/components/response-timer.js | 30 ++++++------ app/ui/components/settings/plugins.js | 12 ++++- app/ui/css/components/modal.less | 20 +------- 8 files changed, 102 insertions(+), 95 deletions(-) diff --git a/app/sync/storage.js b/app/sync/storage.js index b04b2add7..dd0d4c385 100644 --- a/app/sync/storage.js +++ b/app/sync/storage.js @@ -12,6 +12,25 @@ export const SYNC_MODE_OFF = 'paused'; export const SYNC_MODE_ON = 'active'; export const SYNC_MODE_NEVER = 'never'; export const SYNC_MODE_UNSET = 'unset'; +let changeListeners = []; + +export function onChange (callback) { + changeListeners.push(callback); +} + +export function offChange (callback) { + changeListeners = changeListeners.filter(l => l !== callback); +} + +let _changeTimeout = null; +function _notifyChange () { + clearTimeout(_changeTimeout); + _changeTimeout = setTimeout(() => { + for (const fn of changeListeners) { + fn(); + } + }, 200); +} export function allActiveResources (resourceGroupId = null) { if (resourceGroupId) { @@ -86,6 +105,7 @@ export function findResourcesByDocId (id) { export async function removeResourceGroup (resourceGroupId) { await _execDB(TYPE_RESOURCE, 'remove', {resourceGroupId}, {multi: true}); await _execDB(TYPE_CONFIG, 'remove', {resourceGroupId}, {multi: true}); + _notifyChange(); } export async function insertResource (resource) { @@ -94,17 +114,20 @@ export async function insertResource (resource) { h.update(resource.id); const newResource = Object.assign({}, resource, {_id: `rs_${h.digest('hex')}`}); await _execDB(TYPE_RESOURCE, 'insert', newResource); + _notifyChange(); return newResource; } export async function updateResource (resource, ...patches) { const newDoc = Object.assign({}, resource, ...patches); await _execDB(TYPE_RESOURCE, 'update', {_id: resource._id}, newDoc, {multi: true}); + _notifyChange(); return newDoc; } -export function removeResource (resource) { - return _execDB(TYPE_RESOURCE, 'remove', {_id: resource._id}, {multi: true}); +export async function removeResource (resource) { + await _execDB(TYPE_RESOURCE, 'remove', {_id: resource._id}, {multi: true}); + _notifyChange(); } // ~~~~~~ // @@ -196,6 +219,7 @@ export function initDB (config, forceReset) { // ~~~~~~~ // let _database = null; + function _getDB (type, config = {}) { initDB(config); return _database[type]; diff --git a/app/ui/components/base/modal.js b/app/ui/components/base/modal.js index c899d61bf..a6bcd8b48 100644 --- a/app/ui/components/base/modal.js +++ b/app/ui/components/base/modal.js @@ -111,24 +111,17 @@ class Modal extends PureComponent { this.props.onHide && this.props.onHide(); } - componentDidMount () { - this._node.addEventListener('keydown', this._handleKeyDown); - } - - componentWillUnmount () { - if (this._node) { - this._node.removeEventListener('keydown', this._handleKeyDown); - } - } - render () { const {tall, wide, noEscape, className, children} = this.props; const {open, zIndex, forceRefreshCounter} = this.state; + if (!open) { + return null; + } + const classes = classnames( 'modal', className, - {'modal--open': open}, {'modal--fixed-height': tall}, {'modal--noescape': noEscape}, {'modal--wide': wide}, @@ -141,6 +134,7 @@ class Modal extends PureComponent { return (
); } else { - const {syncMode, syncPercent} = syncData; + const {syncMode, syncPercent} = this.state; return (
diff --git a/app/ui/components/modals/request-switcher-modal.js b/app/ui/components/modals/request-switcher-modal.js index c5d673ec2..b1a621c21 100644 --- a/app/ui/components/modals/request-switcher-modal.js +++ b/app/ui/components/modals/request-switcher-modal.js @@ -25,6 +25,25 @@ class RequestSwitcherModal extends PureComponent { }; } + _handleKeydown (e) { + const keyCode = e.keyCode; + + if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) { + // Up or Shift+Tab + this._setActiveIndex(this.state.activeIndex - 1); + } else if (keyCode === 40 || keyCode === 9) { + // Down or Tab + this._setActiveIndex(this.state.activeIndex + 1); + } else if (keyCode === 13) { + // Enter + this._activateCurrentIndex(); + } else { + return; + } + + e.preventDefault(); + } + _setModalRef (n) { this.modal = n; } @@ -186,27 +205,6 @@ class RequestSwitcherModal extends PureComponent { } } - componentDidMount () { - ReactDOM.findDOMNode(this).addEventListener('keydown', e => { - const keyCode = e.keyCode; - - if (keyCode === 38 || (keyCode === 9 && e.shiftKey)) { - // Up or Shift+Tab - this._setActiveIndex(this.state.activeIndex - 1); - } else if (keyCode === 40 || keyCode === 9) { - // Down or Tab - this._setActiveIndex(this.state.activeIndex + 1); - } else if (keyCode === 13) { - // Enter - this._activateCurrentIndex(); - } else { - return; - } - - e.preventDefault(); - }); - } - render () { const { searchString, @@ -219,7 +217,7 @@ class RequestSwitcherModal extends PureComponent { const requestGroups = workspaceChildren.filter(d => d.type === models.requestGroup.type); return ( - +
tab or diff --git a/app/ui/components/response-timer.js b/app/ui/components/response-timer.js index d62323406..e659df2f0 100644 --- a/app/ui/components/response-timer.js +++ b/app/ui/components/response-timer.js @@ -7,7 +7,6 @@ class ResponseTimer extends PureComponent { super(props); this._interval = null; this.state = { - show: false, elapsedTime: 0 }; } @@ -16,24 +15,27 @@ class ResponseTimer extends PureComponent { clearInterval(this._interval); } - componentDidMount () { + componentWillReceiveProps (nextProps) { + const {loadStartTime} = nextProps; + + if (loadStartTime <= 0) { + clearInterval(this._interval); + return; + } + + clearInterval(this._interval); // Just to be sure this._interval = setInterval(() => { - const {loadStartTime} = this.props; - if (loadStartTime > 0) { - // Show and update if needed - const millis = Date.now() - loadStartTime - 200; - const elapsedTime = Math.round(millis / 100) / 10; - this.setState({show: true, elapsedTime}); - } else if (this.state.show) { - // Hide if needed after a small delay (so it doesn't disappear too quickly) - setTimeout(() => this.setState({show: false}), 200); - } + const millis = Date.now() - loadStartTime - 200; + const elapsedTime = Math.round(millis / 100) / 10; + this.setState({elapsedTime}); }, 100); } render () { - const {handleCancel} = this.props; - const {show, elapsedTime} = this.state; + const {handleCancel, loadStartTime} = this.props; + const {elapsedTime} = this.state; + + const show = loadStartTime > 0; return (
diff --git a/app/ui/components/settings/plugins.js b/app/ui/components/settings/plugins.js index 936223644..3b0f5f5fa 100644 --- a/app/ui/components/settings/plugins.js +++ b/app/ui/components/settings/plugins.js @@ -23,6 +23,8 @@ class Plugins extends React.PureComponent { isRefreshingPlugins: boolean }; + _isMounted: boolean; + constructor (props: any) { super(props); this.state = { @@ -75,14 +77,22 @@ class Plugins extends React.PureComponent { const delta = Date.now() - start; await delay(500 - delta); - this.setState({plugins, isRefreshingPlugins: false}); trackEvent('Plugins', 'Refresh'); + + if (this._isMounted) { + this.setState({plugins, isRefreshingPlugins: false}); + } } componentDidMount () { + this._isMounted = true; this._handleRefreshPlugins(); } + componentWillUnmount () { + this._isMounted = false; + } + render () { const {plugins, error, isInstallingFromNpm, isRefreshingPlugins} = this.state; diff --git a/app/ui/css/components/modal.less b/app/ui/css/components/modal.less index 26dc04f2e..2309be5e1 100644 --- a/app/ui/css/components/modal.less +++ b/app/ui/css/components/modal.less @@ -3,22 +3,13 @@ .modal { // Hidden state - opacity: 0; - z-index: -999999; // Component updates this manually - - transition: opacity 250ms; position: absolute; top: 0; - left: -99999px; + left: 0; right: 0; bottom: 0; padding: @padding-lg; - &.modal--open { - opacity: 1; - left: 0; - } - &:focus { outline: 0; } @@ -33,15 +24,11 @@ } .modal__content__wrapper { - top: 1rem; width: @modal-width; height: 100%; max-width: 100%; max-height: 100%; margin: auto; - position: relative; - transform: scale(0.95); - transition: transform 150ms ease-out, top 200ms ease-out; // We want pointer events to pass through to the backdrop so we can close it pointer-events: none; @@ -51,11 +38,6 @@ height: 100%; } - &.modal--open .modal__content__wrapper { - transform: scale(1); - top: 0; - } - &.modal--wide .modal__content__wrapper { width: @modal-width-wide; }