Programmatically change height/width of items in react

Is there a way to programmatically change w and h of an item's layout? The use case is to have a "collapse" button which reduces the height to a constant height, enough to leave the header of the item. To do this my original idea was to keep layouts in the state of the component and manually change the height of the collapsed item/s to another constant height.

However it seems as though the library will ignore changes to layout after initial rendering. Is this the case or is it a bug on my end? And if it's normal behavior, is there another way to change heights programmatically?

Here's a standalone component that implements the react-grid-layout . It's two "widgets" that have an onClick handler to "collapse" them. By setting the state, it triggers the re-render and recalculates layouts so that any collapsed items have a reduced height. The console log statments show that the rendered components have the correct new layout but it does not get reflected on the screen, leading me to believe there is another reference to the height.

jsFiddle example

import React, { Component } from 'react';

import GridLayout, { WidthProvider } from 'react-grid-layout';
const Grid = WidthProvider(GridLayout);

// # WidgetsContainer
// Container WidgetsContainer component.
class WidgetsContainer extends Component {

    static defaultProps = {
        isDraggable: true,
        isResizable: true,
        rowHeight: 1,
        cols: 12,
    }

    constructor(props) {
        super(props);
        this.state = {
            layouts: [
                {
                    i: 'item_1',
                    x: 0,
                    y: 0,
                    w: 5,
                    h: 25,
                }, {
                    i: 'item_2',
                    x: 5,
                    y: 0,
                    w: 7,
                    h: 30,
                },
            ],
            collapsedWidgets: {},
        };
    }

    toggleWidget(id) {
        return () => {
            const newState = {...this.state.collapsedWidgets};
            const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;

            newState[id] = !collapsed;
            this.setState({
                collapsedWidgets: newState,
            });
        }

    }

    onResize(layouts) {
        this.setState({
            layouts,
        });
    }

    getModifiedLayouts() {
        const { layouts, collapsedWidgets } = this.state;

        const newLayouts = layouts.map(layout => {
            const newLayout = { ...layout };
            if (collapsedWidgets[newLayout.i]) {
                newLayout.h = 5;
            }
            return newLayout;
        });

        return newLayouts;
    }

    getWidgets() {
        const widgets = [{
            component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
            title: 'Item 1',
            id: 'item_1',
        }, {
            component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
            title: 'Item 2',
            id: 'item_2',
        }];
        return widgets;
    }

    generateDOM() {
        const widgets = this.getWidgets();

        const modifiedLayouts = this.getModifiedLayouts();

        return widgets.map((widget, i) => {
            return (<div key={i} _grid={modifiedLayouts[i]}>
                <div style={{ background: 'gray' }} onClick={::this.toggleWidget(widget.id)}>
                    {widget.title}
                    {widget.component}
                </div>
            </div>);
        });
    }

    render() {
        const widgets = this.generateDOM();
        console.log(widgets[0].props._grid)
        return (<div style={{ marginTop: '15px' }}>
                {widgets ? <Grid className="layout"
                  {...this.props}
                  onResizeStop={::this.onResize}
                >
                    {widgets}
                </Grid> : null}
            </div>);
    }
}

export default WidgetsContainer;

It turns out the trick is to not use the _grid and instead use the layout prop on the Grid component. Here is a working jsfiddle:

http://jsfiddle.net/zekedroid/d9o75d24/

And the code:

const Grid = ReactGridLayout.WidthProvider(ReactGridLayout);

class Logo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            layouts: [
                {
                    i: '0',
                    x: 0,
                    y: 0,
                    w: 5,
                    h: 25,
                }, {
                    i: '1',
                    x: 5,
                    y: 0,
                    w: 7,
                    h: 30,
                },
            ],
            collapsedWidgets: {},
        };
    }

    toggleWidget(id) {
        return () => {
            const newState = {...this.state.collapsedWidgets};
            const collapsed = typeof newState[id] === 'boolean' ? newState[id] : false;

            newState[id] = !collapsed;
            this.setState({
                collapsedWidgets: newState,
            });
        }

    }

    onResize(layouts) {
        this.setState({
            layouts,
        });
    }

    getModifiedLayouts() {
        const { layouts, collapsedWidgets } = this.state;

        const newLayouts = layouts.map(layout => {
            const newLayout = { ...layout };
            if (collapsedWidgets[newLayout.i]) {
                newLayout.h = 5;
            }
            return newLayout;
        });

        return newLayouts;
    }

    getWidgets() {
        const widgets = [{
            component: <div style={{ height: '250px', background: 'lightgray' }}>Content</div>,
            title: 'Item 1',
            id: '0',
        }, {
            component: <div style={{ height: '310px', background: 'lightgray' }}>Content 2</div>,
            title: 'Item 2',
            id: '1',
        }];
        return widgets;
    }

    generateDOM() {
        const widgets = this.getWidgets();

        return widgets.map((widget, i) => {
            return (<div key={i} style={{ overflowY: 'auto' }}>
                <div style={{ background: 'gray' }} onClick={this.toggleWidget(widget.id).bind(this)}>
                    {widget.title}
                    {widget.component}
                </div>
            </div>);
        });
    }

    render() {
        const widgets = this.generateDOM();

        const modifiedLayouts = this.getModifiedLayouts();

        return (<div style={{ marginTop: '15px' }}>
                {widgets ? <Grid className="layout"
                  {...this.props}
                  onResizeStop={this.onResize.bind(this)}
                  layout={modifiedLayouts}
                >
                    {widgets}
                </Grid> : null}
            </div>);
    }
}

Logo.defaultProps = {
        isDraggable: true,
        isResizable: true,
        rowHeight: 1,
        cols: 12,
    }



React.render( <Logo /> , document.getElementById('container'));
链接地址: http://www.djcxy.com/p/32520.html

上一篇: TF记录和记录混洗

下一篇: 以编程方式更改反应中物品的高度/宽度