From dfd3ba8c14859ccff49c84f542eaba7189cc2a2f Mon Sep 17 00:00:00 2001 From: Matthew Dapena-Tretter Date: Mon, 2 Apr 2018 17:10:37 -0700 Subject: [PATCH] Defer component initialization until element is requested This fixes the error snapshotting Docks described in #16864. --- src/dock.js | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/src/dock.js b/src/dock.js index 7ed18972c..dc77365fb 100644 --- a/src/dock.js +++ b/src/dock.js @@ -50,7 +50,6 @@ module.exports = class Dock { }) this.state = { - ready: false, size: null, visible: false, shouldAnimate: false @@ -70,8 +69,6 @@ module.exports = class Dock { this.paneContainer.onDidChangeActivePaneItem((item) => params.didChangeActivePaneItem(this, item)), this.paneContainer.onDidDestroyPaneItem((item) => params.didDestroyPaneItem(item)) ) - - etch.initialize(this) } // This method is called explicitly by the object which adds the Dock to the document. @@ -81,11 +78,11 @@ module.exports = class Dock { } getElement () { - if (!this.state.ready) { - // Render the element with its contents for the first time. This needs to be deferred so it's - // not done when snapshotting. - this.setState({ready: true}) - etch.updateSync(this) + // Because this code is included in the snapshot, we have to make sure we don't touch the DOM + // during initialization. Therefore, we defer initialization of the component (which creates a + // DOM element) until somebody asks for the element. + if (this.element == null) { + etch.initialize(this) } return this.element } @@ -166,8 +163,10 @@ module.exports = class Dock { // Render immediately if the dock becomes visible or the size changes in case people are // measuring after opening, for example. - if ((visible && !prevState.visible) || (this.state.size !== prevState.size)) etch.updateSync(this) - else etch.update(this) + if (this.element != null) { + if ((visible && !prevState.visible) || (this.state.size !== prevState.size)) etch.updateSync(this) + else etch.update(this) + } if (hovered !== prevState.hovered) { this.emitter.emit('did-change-hovered', hovered) @@ -178,14 +177,6 @@ module.exports = class Dock { } render () { - const atomDock = children => $('atom-dock', {className: this.location}, children) - - // Because this code is included in the snapshot, we have to make sure we don't load - // DOM-touching classes (like PaneContainerElement) during initialization. The way we do this - // is by avoiding rendering the full contents until the element is attached, at which point we - // toggle the `ready` state and render the full dock contents. - if (!this.state.ready) return atomDock([]) - const innerElementClassList = ['atom-dock-inner', this.location] if (this.state.visible) innerElementClassList.push(VISIBLE_CLASS) @@ -207,7 +198,9 @@ module.exports = class Dock { // ...but the content needs to maintain a constant size. const wrapperStyle = {[this.widthOrHeight]: `${size}px`} - return atomDock( + return $( + 'atom-dock', + {className: this.location}, $.div( {ref: 'innerElement', className: innerElementClassList.join(' ')}, $.div(