Browse Source

Merge pull request #596 from gre/growscroll-perf

refactor GrowScroll to be performant
master
Gaëtan Renaudeau 7 years ago
committed by GitHub
parent
commit
142d9d9c34
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      package.json
  2. 34
      src/components/StickyBackToTop.js
  3. 1
      src/components/base/Box/Box.js
  4. 139
      src/components/base/GrowScroll/index.js
  5. 2
      src/components/layout/Default.js
  6. 2
      src/main/app.js
  7. 16
      yarn.lock

2
package.json

@ -82,7 +82,6 @@
"react-router-dom": "^4.3.1",
"react-router-redux": "5.0.0-alpha.9",
"react-select": "2.0.0-beta.6",
"react-smooth-scrollbar": "^8.0.6",
"react-spring": "^5.3.15",
"redux": "^4.0.0",
"redux-actions": "^2.4.0",
@ -97,7 +96,6 @@
"secp256k1": "3.3.1",
"semaphore": "^1.1.0",
"semver": "^5.5.0",
"smooth-scrollbar": "^8.2.7",
"source-map": "0.7.3",
"source-map-support": "^0.5.4",
"styled-components": "^3.3.2",

34
src/components/StickyBackToTop.js

@ -1,10 +1,10 @@
// @flow
import React, { PureComponent } from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import Box from 'components/base/Box'
import AngleUp from 'icons/AngleUp'
import { GrowScrollContext } from './base/GrowScroll'
const Container = styled(Box)`
position: fixed;
@ -29,6 +29,7 @@ const Container = styled(Box)`
type Props = {
scrollThreshold: number,
getGrowScroll: () => { scrollContainer: ?HTMLDivElement },
}
type State = {
@ -36,11 +37,6 @@ type State = {
}
class StickyBackToTop extends PureComponent<Props, State> {
static contextTypes = {
// FIXME when we move to "real" scroll container, potential solution (instead of context): http://greweb.me/2016/09/relay-scrolling-connections/
getScrollbar: PropTypes.func,
}
static defaultProps = {
scrollThreshold: 800,
}
@ -50,10 +46,10 @@ class StickyBackToTop extends PureComponent<Props, State> {
}
componentDidMount() {
if (!this.context.getScrollbar) return
this.context.getScrollbar(scrollbar => {
const { scrollContainer } = this.props.getGrowScroll()
if (scrollContainer) {
const listener = () => {
const { scrollTop } = scrollbar
const { scrollTop } = scrollContainer
const visible = scrollTop > this.props.scrollThreshold
this.setState(previous => {
if (previous.visible !== visible) {
@ -62,9 +58,9 @@ class StickyBackToTop extends PureComponent<Props, State> {
return null
})
}
scrollbar.addListener(listener)
this.releaseListener = () => scrollbar.removeListener(listener)
})
scrollContainer.addEventListener('scroll', listener)
this.releaseListener = () => scrollContainer.addEventListener('scroll', listener)
}
}
componentWillUnmount() {
@ -72,9 +68,11 @@ class StickyBackToTop extends PureComponent<Props, State> {
}
onClick = () => {
this.context.getScrollbar(scrollbar => {
scrollbar.scrollTo(0, 0, 400)
})
const { scrollContainer } = this.props.getGrowScroll()
if (scrollContainer) {
// $FlowFixMe seems to be missing in flow
scrollContainer.scrollTo(0, 0)
}
}
releaseListener = () => {}
@ -92,4 +90,8 @@ class StickyBackToTop extends PureComponent<Props, State> {
}
}
export default StickyBackToTop
export default (props: { scrollThreshold?: number }) => (
<GrowScrollContext.Consumer>
{getGrowScroll => <StickyBackToTop {...props} getGrowScroll={getGrowScroll} />}
</GrowScrollContext.Consumer>
)

1
src/components/base/Box/Box.js

@ -40,6 +40,7 @@ export default styled.div`
flex-grow: ${p => (p.grow === true ? '1' : p.grow || '')};
flex-direction: ${p => (p.horizontal ? 'row' : 'column')};
overflow: ${p => p.overflow};
overflow-y: ${p => (p.scroll === true ? 'auto' : '')};
position: ${p => (p.relative ? 'relative' : p.sticky ? 'absolute' : '')};

139
src/components/base/GrowScroll/index.js

@ -1,116 +1,79 @@
// @flow
/* eslint-disable class-methods-use-this */
import React, { PureComponent } from 'react'
import Scrollbar from 'react-smooth-scrollbar'
import SmoothScrollbar, { ScrollbarPlugin } from 'smooth-scrollbar'
import Box from 'components/base/Box'
type Props = {
children: any,
full: boolean,
maxHeight?: number,
onUpdate?: (*) => void,
onScroll?: () => void,
}
// TODO this component is the source of junky scroll experience. need better solution ASAP
export const GrowScrollContext = React.createContext()
class GrowScroll extends PureComponent<Props> {
static defaultProps = {
full: false,
}
componentDidMount() {
const { onUpdate, onScroll } = this.props
const { _scrollbar } = this
if (_scrollbar) {
if (onUpdate) {
onUpdate(_scrollbar)
}
if (onScroll) {
_scrollbar.addListener(this.onScroll)
}
}
}
componentWillUnmount() {
const { onScroll } = this.props
const { _scrollbar } = this
if (_scrollbar && onScroll) {
_scrollbar.removeListener(this.onScroll)
}
}
scrollContainer: ?HTMLDivElement
componenDidUpdate() {
const { onUpdate } = this.props
const { _scrollbar } = this
if (_scrollbar && onUpdate) {
onUpdate(_scrollbar)
}
onScrollContainerRef = (scrollContainer: ?HTMLDivElement) => {
this.scrollContainer = scrollContainer
}
onScroll = () => {
const { onScroll } = this.props
if (onScroll) onScroll()
}
onRef = (ref: ?Scrollbar) => {
this._scrollbar = ref && ref.scrollbar
}
_scrollbar: *
valueProvider = () => ({
scrollContainer: this.scrollContainer,
})
render() {
const { onUpdate, children, maxHeight, full, ...props } = this.props
const { children, maxHeight, full, ...props } = this.props
const rootStyles = {
overflow: 'hidden',
...(full
? {
top: 0,
left: 0,
right: 0,
bottom: 0,
}
: {
display: 'flex',
flex: 1,
positoin: 'relative',
}),
}
const scrollContainerStyles = {
overflowY: 'auto',
marginRight: `-80px`,
paddingRight: `80px`,
...(maxHeight
? {
maxHeight,
}
: {
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
}),
}
return (
<Box
{...(full
? {
sticky: true,
}
: {
grow: true,
relative: true,
})}
>
<Scrollbar
damping={1}
style={{
...(maxHeight
? {
maxHeight,
}
: {
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0,
}),
}}
ref={this.onRef}
>
<Box {...props}>{children}</Box>
</Scrollbar>
</Box>
<div style={rootStyles}>
<div style={scrollContainerStyles} ref={this.onScrollContainerRef}>
<Box {...props}>
<GrowScrollContext.Provider value={this.valueProvider}>
{children}
</GrowScrollContext.Provider>
</Box>
</div>
</div>
)
}
}
SmoothScrollbar.use(
class DisableXScroll extends ScrollbarPlugin {
static pluginName = 'disableXScroll'
transformDelta(delta) {
return {
x: 0,
y: delta.y,
}
}
},
)
export default GrowScroll

2
src/components/layout/Default.js

@ -74,7 +74,7 @@ class Default extends Component<Props> {
<Box grow horizontal bg="white">
<SideBar />
<Box shrink grow bg="lightGrey" color="grey" relative>
<Box shrink grow bg="lightGrey" color="grey" overflow="hidden" relative>
<TopBar />
<Main innerRef={n => (this._scrollContainer = n)} tabIndex={-1}>
<Route path="/" exact component={DashboardPage} />

2
src/main/app.js

@ -67,7 +67,7 @@ const defaultWindowOptions = {
}
function createMainWindow() {
const MIN_HEIGHT = 720
const MIN_HEIGHT = 768
const MIN_WIDTH = 1024
const savedDimensions = db.getIn('settings', 'window.MainWindow.dimensions', {})

16
yarn.lock

@ -4634,7 +4634,7 @@ core-js@^1.0.0:
version "1.2.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.1, core-js@^2.5.3, core-js@^2.5.6:
core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.5.3, core-js@^2.5.6:
version "2.5.7"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
@ -11664,10 +11664,6 @@ react-select@2.0.0-beta.6:
react-input-autosize "^2.2.1"
react-transition-group "^2.2.1"
react-smooth-scrollbar@^8.0.6:
version "8.0.6"
resolved "https://registry.yarnpkg.com/react-smooth-scrollbar/-/react-smooth-scrollbar-8.0.6.tgz#179072e6a547b3af589ea303c50fd86366275edc"
react-split-pane@^0.1.77:
version "0.1.77"
resolved "https://registry.yarnpkg.com/react-split-pane/-/react-split-pane-0.1.77.tgz#f0c8cd18d076bbac900248dcf6dbcec02d5340db"
@ -12812,14 +12808,6 @@ smart-buffer@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.0.1.tgz#07ea1ca8d4db24eb4cac86537d7d18995221ace3"
smooth-scrollbar@^8.2.7:
version "8.2.7"
resolved "https://registry.yarnpkg.com/smooth-scrollbar/-/smooth-scrollbar-8.2.7.tgz#41a3f84ee4677ae7a417081e3384e1e15ebcdb86"
dependencies:
core-js "^2.5.1"
lodash-es "^4.17.4"
tslib "^1.7.1"
snapdragon-node@^2.0.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
@ -13697,7 +13685,7 @@ tryer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7"
tslib@^1.7.1, tslib@^1.9.0:
tslib@^1.9.0:
version "1.9.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.2.tgz#8be0cc9a1f6dc7727c38deb16c2ebd1a2892988e"

Loading…
Cancel
Save