From 1decff1bf364d86b8b175e6733283d1e2109bef5 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Tue, 6 Mar 2018 15:45:31 +0900 Subject: [PATCH] Extract columns area from UI component (#6650) UI component used to toggle isComposing state by directly manipulating the DOM element to avoid the expensive rendering. However, it is hacky, and is not effective for other states. Instead, this change makes the rendering cheaper by extracting the huge columns area. --- app/javascript/mastodon/features/ui/index.js | 163 +++++++++++-------- 1 file changed, 93 insertions(+), 70 deletions(-) diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index ef909136f8..9960758afa 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -1,3 +1,4 @@ +import classNames from 'classnames'; import React from 'react'; import NotificationsContainer from './containers/notifications_container'; import PropTypes from 'prop-types'; @@ -84,10 +85,93 @@ const keyMap = { goToMuted: 'g m', }; +class SwitchingColumnsArea extends React.PureComponent { + + static propTypes = { + children: PropTypes.node, + location: PropTypes.object, + onLayoutChange: PropTypes.func.isRequired, + }; + + state = { + mobile: isMobile(window.innerWidth), + }; + + componentWillMount () { + window.addEventListener('resize', this.handleResize, { passive: true }); + } + + componentDidUpdate (prevProps) { + if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { + this.node.handleChildrenContentChange(); + } + } + + componentWillUnmount () { + window.removeEventListener('resize', this.handleResize); + } + + handleResize = debounce(() => { + // The cached heights are no longer accurate, invalidate + this.props.onLayoutChange(); + + this.setState({ mobile: isMobile(window.innerWidth) }); + }, 500, { + trailing: true, + }); + + setRef = c => { + this.node = c.getWrappedInstance().getWrappedInstance(); + } + + render () { + const { children } = this.props; + const { mobile } = this.state; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + +} + @connect(mapStateToProps) @injectIntl @withRouter -export default class UI extends React.Component { +export default class UI extends React.PureComponent { static contextTypes = { router: PropTypes.object.isRequired, @@ -103,7 +187,6 @@ export default class UI extends React.Component { }; state = { - width: window.innerWidth, draggingOver: false, }; @@ -118,14 +201,10 @@ export default class UI extends React.Component { } } - handleResize = debounce(() => { + handleLayoutChange = () => { // The cached heights are no longer accurate, invalidate this.props.dispatch(clearHeight()); - - this.setState({ width: window.innerWidth }); - }, 500, { - trailing: true, - }); + } handleDragEnter = (e) => { e.preventDefault(); @@ -193,7 +272,6 @@ export default class UI extends React.Component { componentWillMount () { window.addEventListener('beforeunload', this.handleBeforeUnload, false); - window.addEventListener('resize', this.handleResize, { passive: true }); document.addEventListener('dragenter', this.handleDragEnter, false); document.addEventListener('dragover', this.handleDragOver, false); document.addEventListener('drop', this.handleDrop, false); @@ -214,28 +292,8 @@ export default class UI extends React.Component { }; } - shouldComponentUpdate (nextProps) { - if (nextProps.isComposing !== this.props.isComposing) { - // Avoid expensive update just to toggle a class - this.node.classList.toggle('is-composing', nextProps.isComposing); - - return false; - } - - // Why isn't this working?!? - // return super.shouldComponentUpdate(nextProps, nextState); - return true; - } - - componentDidUpdate (prevProps) { - if (![this.props.location.pathname, '/'].includes(prevProps.location.pathname)) { - this.columnsAreaNode.handleChildrenContentChange(); - } - } - componentWillUnmount () { window.removeEventListener('beforeunload', this.handleBeforeUnload); - window.removeEventListener('resize', this.handleResize); document.removeEventListener('dragenter', this.handleDragEnter); document.removeEventListener('dragover', this.handleDragOver); document.removeEventListener('drop', this.handleDrop); @@ -247,10 +305,6 @@ export default class UI extends React.Component { this.node = c; } - setColumnsAreaRef = c => { - this.columnsAreaNode = c.getWrappedInstance().getWrappedInstance(); - } - handleHotkeyNew = e => { e.preventDefault(); @@ -350,8 +404,8 @@ export default class UI extends React.Component { } render () { - const { width, draggingOver } = this.state; - const { children } = this.props; + const { draggingOver } = this.state; + const { children, isComposing, location } = this.props; const handlers = { help: this.handleHotkeyToggleHelp, @@ -374,43 +428,12 @@ export default class UI extends React.Component { return ( -
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + {children} +