From 8d69d31cd23ebfaf585daa3093e70da49496daee Mon Sep 17 00:00:00 2001 From: Samuel Reed Date: Thu, 14 Apr 2016 14:46:20 -0500 Subject: [PATCH] Fix for #212 - provide a method for eliminating animation on mount. --- .flowconfig | 10 ++--- README.md | 4 ++ examples/example-styles.css | 1 + lib/components/WidthProvider.jsx | 32 ++++++++++---- test/examples/0-showcase.jsx | 74 ++++++++++++++++---------------- 5 files changed, 71 insertions(+), 50 deletions(-) diff --git a/.flowconfig b/.flowconfig index 79e963124..7c524057a 100644 --- a/.flowconfig +++ b/.flowconfig @@ -11,10 +11,10 @@ index.js [libs] [options] -suppress_comment=.*\\\\s*$FlowFixMe.* -suppress_comment=.*\\\\s*$FlowBug.* -suppress_comment=.*\\\\s*$FlowIgnore.* -suppress_comment=\\(.\\|\n\\)*\\$FlowNewLine.* -suppress_comment=\\(.\\|\n\\)*\\$FlowIssue +suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowFixMe.* +suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowBug.* +suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIgnore.* +suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowNewLine.* +suppress_comment=\\(.\\|\n\\)*\\s*\\$FlowIssue esproposal.class_instance_fields=ignore esproposal.class_static_fields=ignore diff --git a/README.md b/README.md index 653ea74a6..a43f4dffd 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,10 @@ render: function() { This allows you to easily replace `` with your own Provider HOC if you need more sophisticated logic. +`` accepts a single prop, `measureBeforeMount`. If `true`, `` will measure the +container's width before mounting children. Use this if you'd like to completely eliminate any resizing animation +on application/component mount. + ### Grid Layout Props diff --git a/examples/example-styles.css b/examples/example-styles.css index 6e973101c..354c624bf 100644 --- a/examples/example-styles.css +++ b/examples/example-styles.css @@ -1,6 +1,7 @@ body { background: white; padding: 20px; + overflow: scroll; } #content { width: 100%; diff --git a/lib/components/WidthProvider.jsx b/lib/components/WidthProvider.jsx index 409b90364..90ac8f2f6 100644 --- a/lib/components/WidthProvider.jsx +++ b/lib/components/WidthProvider.jsx @@ -3,26 +3,38 @@ import React from "react"; import ReactDOM from 'react-dom'; -type State = {width: number}; +type State = { + mounted: boolean, + width: number +}; /* * A simple HOC that provides facility for listening to container resizes. */ export default (ComposedComponent: ReactClass): ReactClass => class extends React.Component { + static defaultProps = { + measureBeforeMount: false + }; + + static propTypes = { + // If true, will not render children until mounted. Useful for getting the exact width before + // rendering, to prevent any unsightly resizing. + measureBeforeMount: React.PropTypes.bool + }; + state: State = { + mounted: false, width: 1280 }; componentDidMount() { - const node = ReactDOM.findDOMNode(this); - // Bind here so we have the same reference when removing the listener on unmount. - this.onWindowResize = this._onWindowResize.bind(this, node); + this.setState({mounted: true}); window.addEventListener('resize', this.onWindowResize); - // This is intentional. Once to properly set the breakpoint and resize the elements, - // and again to compensate for any scrollbar that appeared because of the first step. - this.onWindowResize(); + // Call to properly set the breakpoint and resize the elements. + // Note that if you're doing a full-width element, this can get a little wonky if a scrollbar + // appears because of the grid. In that case, fire your own resize event, or set `overflow: scroll` on your body. this.onWindowResize(); } @@ -30,11 +42,13 @@ export default (ComposedComponent: ReactClass): ReactClass => class extends Reac window.removeEventListener('resize', this.onWindowResize); } - _onWindowResize(node: HTMLElement, _event: Event) { - this.setState({width: node.offsetWidth}); + onWindowResize = (_event: Event, cb: ?Function) => { + const node = ReactDOM.findDOMNode(this); + this.setState({width: node.offsetWidth}, cb); } render() { + if (this.props.measureBeforeMount && !this.state.mounted) return
; return ; } }; diff --git a/test/examples/0-showcase.jsx b/test/examples/0-showcase.jsx index 4fd5a76d8..1834a913c 100644 --- a/test/examples/0-showcase.jsx +++ b/test/examples/0-showcase.jsx @@ -1,33 +1,31 @@ -'use strict'; -var React = require('react'); -var PureRenderMixin = require('react/lib/ReactComponentWithPureRenderMixin'); -var _ = require('lodash'); -var WidthProvider = require('react-grid-layout').WidthProvider; -var ResponsiveReactGridLayout = require('react-grid-layout').Responsive; -ResponsiveReactGridLayout = WidthProvider(ResponsiveReactGridLayout); +import React from 'react'; +import PureRenderMixin from 'react/lib/ReactComponentWithPureRenderMixin'; +import _ from 'lodash'; +import {Responsive, WidthProvider} from 'react-grid-layout'; +const ResponsiveReactGridLayout = WidthProvider(Responsive); -var BasicLayout = React.createClass({ - mixins: [PureRenderMixin], +class ShowcaseLayout extends React.Component { - propTypes: { + static propTypes = { onLayoutChange: React.PropTypes.func.isRequired - }, + }; - getDefaultProps() { - return { - className: "layout", - rowHeight: 30, - cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}, - initialLayout: generateLayout() - }; - }, + static defaultProps = { + className: "layout", + rowHeight: 30, + cols: {lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}, + initialLayout: generateLayout() + }; - getInitialState() { - return { - layouts: {lg: this.props.initialLayout}, - currentBreakpoint: 'lg' - }; - }, + state = { + currentBreakpoint: 'lg', + mounted: false, + layouts: {lg: this.props.initialLayout}, + }; + + componentDidMount() { + this.setState({mounted: true}); + } generateDOM() { return _.map(this.state.layouts.lg, function (l, i) { @@ -39,23 +37,23 @@ var BasicLayout = React.createClass({ }
); }); - }, + } - onBreakpointChange(breakpoint) { + onBreakpointChange = (breakpoint) => { this.setState({ currentBreakpoint: breakpoint }); - }, + }; - onLayoutChange(layout, layouts) { + onLayoutChange = (layout, layouts) => { this.props.onLayoutChange(layout, layouts); - }, + }; - onNewLayout() { + onNewLayout = () => { this.setState({ layouts: {lg: generateLayout()} }); - }, + }; render() { return ( @@ -68,13 +66,19 @@ var BasicLayout = React.createClass({ layouts={this.state.layouts} onBreakpointChange={this.onBreakpointChange} onLayoutChange={this.onLayoutChange} - useCSSTransforms={true}> + // WidthProvider option + measureBeforeMount={false} + // I like to have it animate on mount. If you don't, delete `useCSSTransforms` (it's default `true`) + // and set `measureBeforeMount={true}`. + useCSSTransforms={this.state.mounted}> {this.generateDOM()} ); } -}); +} + +module.exports = ShowcaseLayout; function generateLayout() { return _.map(_.range(0, 25), function (item, i) { @@ -90,8 +94,6 @@ function generateLayout() { }); } -module.exports = BasicLayout; - if (require.main === module) { require('../test-hook.jsx')(module.exports); }