From 5a9a3c62e140aedf3416cc7b99401bb06255c199 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 16 Apr 2014 12:19:18 -0600 Subject: [PATCH] Implement shouldComponentUpdate for LinesComponent We accumulate pending changes and pass them to the lines and the gutter to help them determine whether to update. The lines only update if the visible row range changed or if there was a change in the visible row range. --- src/editor-component.coffee | 11 +++++++---- src/editor-scroll-view-component.coffee | 4 ++-- src/gutter-component.coffee | 14 ++------------ src/lines-component.coffee | 11 ++++++++++- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/editor-component.coffee b/src/editor-component.coffee index 6a45168ae..172e66707 100644 --- a/src/editor-component.coffee +++ b/src/editor-component.coffee @@ -28,10 +28,10 @@ EditorComponent = React.createClass className += ' is-focused' if focused div className: className, style: {fontSize, lineHeight, fontFamily}, tabIndex: -1, onFocus: @onFocus, - GutterComponent({editor, visibleRowRange, scrollTop}) + GutterComponent({editor, visibleRowRange, scrollTop, @pendingChanges}) EditorScrollViewComponent { - ref: 'scrollView', editor, visibleRowRange, @onInputFocused, @onInputBlurred + ref: 'scrollView', editor, visibleRowRange, @pendingChanges, @onInputFocused, @onInputBlurred cursorBlinkPeriod, cursorBlinkResumeDelay, showIndentGuide, fontSize, fontFamily, lineHeight } @@ -58,6 +58,7 @@ EditorComponent = React.createClass cursorBlinkResumeDelay: 200 componentDidMount: -> + @pendingChanges = [] @props.editor.manageScrollPosition = true @listenForDOMEvents() @@ -72,6 +73,7 @@ EditorComponent = React.createClass @stopBlinkingCursors() componentDidUpdate: -> + @pendingChanges.length = 0 @props.parentView.trigger 'editor:display-updated' observeEditor: -> @@ -272,9 +274,10 @@ EditorComponent = React.createClass if updateRequested @forceUpdate() - onScreenLinesChanged: ({start, end}) -> + onScreenLinesChanged: (change) -> {editor} = @props - @requestUpdate() if editor.intersectsVisibleRowRange(start, end + 1) # TODO: Use closed-open intervals for change events + @pendingChanges.push(change) + @requestUpdate() if editor.intersectsVisibleRowRange(change.start, change.end + 1) # TODO: Use closed-open intervals for change events onSelectionAdded: (selection) -> {editor} = @props diff --git a/src/editor-scroll-view-component.coffee b/src/editor-scroll-view-component.coffee index dd1937e2f..d0aec653b 100644 --- a/src/editor-scroll-view-component.coffee +++ b/src/editor-scroll-view-component.coffee @@ -12,7 +12,7 @@ EditorScrollViewComponent = React.createClass render: -> {editor, fontSize, fontFamily, lineHeight, showIndentGuide, cursorBlinkPeriod, cursorBlinkResumeDelay} = @props - {visibleRowRange, onInputFocused, onInputBlurred} = @props + {visibleRowRange, pendingChanges, onInputFocused, onInputBlurred} = @props contentStyle = height: editor.getScrollHeight() WebkitTransform: "translate(#{-editor.getScrollLeft()}px, #{-editor.getScrollTop()}px)" @@ -28,7 +28,7 @@ EditorScrollViewComponent = React.createClass div className: 'scroll-view-content', style: contentStyle, onMouseDown: @onMouseDown, CursorsComponent({editor, cursorBlinkPeriod, cursorBlinkResumeDelay}) - LinesComponent({ref: 'lines', editor, fontSize, fontFamily, lineHeight, visibleRowRange, showIndentGuide}) + LinesComponent({ref: 'lines', editor, fontSize, fontFamily, lineHeight, visibleRowRange, pendingChanges, showIndentGuide}) div className: 'underlayer', SelectionsComponent({editor}) diff --git a/src/gutter-component.coffee b/src/gutter-component.coffee index 4fcff9828..7ab6c4846 100644 --- a/src/gutter-component.coffee +++ b/src/gutter-component.coffee @@ -41,10 +41,6 @@ GutterComponent = React.createClass div className: 'spacer', key: 'bottom-spacer', style: {height: followingHeight} ] - componentDidMount: -> - @pendingChanges = [] - @subscribe @props.editor, 'screen-lines-changed', @onScreenLinesChanged - componentWillUnmount: -> @unsubscribe() @@ -52,22 +48,16 @@ GutterComponent = React.createClass # non-zero-delta change to the screen lines has occurred within the current # visible row range. shouldComponentUpdate: (newProps) -> - {visibleRowRange, scrollTop} = @props + {visibleRowRange, pendingChanges, scrollTop} = @props return true unless newProps.scrollTop is scrollTop return true unless isEqual(newProps.visibleRowRange, visibleRowRange) - for change in @pendingChanges when change.screenDelta > 0 or change.bufferDelta > 0 + for change in pendingChanges when change.screenDelta > 0 or change.bufferDelta > 0 return true unless change.end <= visibleRowRange.start or visibleRowRange.end <= change.start false - componentDidUpdate: -> - @pendingChanges.length = 0 - - onScreenLinesChanged: (change) -> - @pendingChanges.push(change) - LineNumberComponent = React.createClass displayName: 'LineNumberComponent' diff --git a/src/lines-component.coffee b/src/lines-component.coffee index 9b9e8d5c5..e3d81ab5e 100644 --- a/src/lines-component.coffee +++ b/src/lines-component.coffee @@ -1,6 +1,6 @@ React = require 'react' {div, span} = require 'reactionary' -{debounce, isEqualForProperties, multiplyString} = require 'underscore-plus' +{debounce, isEqual, isEqualForProperties, multiplyString} = require 'underscore-plus' {$$} = require 'space-pen' DummyLineNode = $$(-> @div className: 'line', style: 'position: absolute; visibility: hidden;', => @span 'x')[0] @@ -28,6 +28,15 @@ LinesComponent = React.createClass @measuredLines = new WeakSet @updateModelDimensions() + shouldComponentUpdate: (newProps) -> + return true unless isEqualForProperties(newProps, @props, 'visibleRowRange', 'fontSize', 'fontFamily', 'lineHeight', 'showIndentGuide') + + {visibleRowRange, pendingChanges} = newProps + for change in pendingChanges + return true unless change.end <= visibleRowRange.start or visibleRowRange.end <= change.start + + false + componentDidUpdate: (prevProps) -> @updateModelDimensions() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily', 'lineHeight') @clearScopedCharWidths() unless isEqualForProperties(prevProps, @props, 'fontSize', 'fontFamily')