通过组件反应提升状态

时间:2017-03-25 17:19:45

标签: reactjs react-native react-router react-redux

我无法绕过这个问题。我正在写一个仪表板应用程序,以反应。我试图保持良好和模块化。我有两个布局类“row.js”& “col.js”他们基本上是返回bootstrap响应网格元素,“col-sm-3”等。

我创建了一个widget类和一个widget-expandable类。窗口小部件类返回带有一些样式的div,窗口小部件可扩展类扩展窗口小部件类,并添加一个单击处理程序以扩展到完整的浏览器宽度。然后我创建自定义窗口小部件类,以扩展这些窗口小部件类。这些自定义类将图形或表格等添加到实际组件中。我试图解决的问题是:

在我的dashboard.jsx中,我有:

<Row>
    <Col size="sm" num="3"> 
        <SpeakerFees expanded={false}/>
    </Col>
    <Col size="sm" num="9">
        <ProgramStatusByZoneOverview />
    </Col>
</Row>

我想点击窗口小部件组件,将其传递给最近的祖先,“”并警告同一行中的其他窗口小部件。根据反应提升状态文档,我们应该提升到最近的祖先。在这种情况下,两个元素向上。这很讨厌lol

因为仪表板的布局最多只包含10个小部件,所以我认为最好只是在dashboard.jsx中对它们进行硬编码,而不是使用某种循环。以下是我的其他课程。

dashboard.jsx

var React = require('react');
var ReactDOM = require('react-dom');

import { Row } from './layout/row.jsx';
import { Col } from './layout/col.jsx';

import { TotalWidget } from './widgets/total-widget.jsx';
import { ProgramsPlannedBySeries } from './widgets/programs-planned-by-series.jsx';
import { SpeakerFees } from './widgets/speaker-fees.jsx';
import { ProgramStatusByZoneOverview } from './widgets/program-status-by-zone-overview.jsx';

import 'bootstrap/dist/css/bootstrap.css';
import '../styles/app.scss';

class Dashboard extends React.Component {
    render() {
        var list = [
            {
                "size": "sm",
                "num": "3"
            },{
                "size": "sm",
                "num": "3"
            },{
                "size": "sm",
                "num": "3"
            },{
                "size": "sm",
                "num": "3"
            }
        ]
        return (
            <div className="container">
                <Row>
                    {list.map(function(object, i){
                        return (
                            <Col key={i.toString()} size={object.size} num={object.num}><TotalWidget key={i.toString()} /></Col>
                        );
                    })}
                </Row>
                <Row>
                    <Col size="sm" num="12">
                        <ProgramsPlannedBySeries />
                    </Col>
                </Row>
                <Row>
                    <Col size="sm" num="3"> 
                        <SpeakerFees expanded={false}/>
                    </Col>
                    <Col size="sm" num="9">
                        <ProgramStatusByZoneOverview />
                    </Col>
                </Row>
                <Row>
                    <Col size="sm" num="3"> 
                        <SpeakerFees expanded={false}/>
                    </Col>
                    <Col size="sm" num="9">
                        <ProgramStatusByZoneOverview />
                    </Col>
                </Row>
                <Row>
                    <Col size="sm" num="3"> 
                        <SpeakerFees expanded={false}/>
                    </Col>
                    <Col size="sm" num="9">
                        <ProgramStatusByZoneOverview />
                    </Col>
                </Row>
            </div>
        );
    }
}

ReactDOM.render(<Dashboard />, document.getElementById('widgets-wrapper')); 

和我的小部件类:

widget.jsx
var React = require('react');

import {TweenMax, Power2, TimelineLite} from "gsap";

export class WidgetMenu extends React.Component {
    constructor() {
        super();
        this.click = this.click.bind(this);
    }
    click() {
        alert()
    }
    render() {
        return (
            <span onClick={this.click} className={"glyphicon glyphicon-option-horizontal elipsis " + this.props.state} ></span>
        );
    }
}

export class Widget extends React.Component {
    constructor(props) {
        super(props);
        this.state = {'scale': false, 'class': ''};
        this.hover = this.hover.bind(this);
    }
    hover() {
        if(!this.state.scale){
            this.setState({'scale': true, 'class': 'scaleUp'})
        }else{
            this.setState({'scale': false, 'class': ''})
        }
    }
    click() {
        // alsert('widget')
    }
    render() {
        return (
              <div onClick={this.click} onMouseEnter={this.hover} onMouseLeave={this.hover} className="widget"><WidgetMenu state={this.state.class} />{ this.props.children }</div>
            )
    }
}

和widget-expandable.jsx

widget-expandable.jsx
import { Widget, WidgetMenu } from './widget.jsx';
var React = require('react');

export class WidgetExpandable extends Widget {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div onMouseEnter={this.hover} onMouseLeave={this.hover} className="widget"><WidgetMenu state={this.state.class} />{ this.props.children }</div>
        )
    }

}

以下两个自定义小部件将是dashboard.jsx中的cols / rows:

speaker-fee.jsx
"use strict";
var React = require('react');
var Highcharts = require('highcharts');

import { WidgetExpandable } from './widget-expandable.jsx';

export class SpeakerFees extends React.Component {
    render() {
        return (
            <WidgetExpandable handleClick={this.props.handleClick}>
                <div id="speaker-fees-chart"></div>
            </WidgetExpandable>
        );
    } 
}

program-status.jsx
"use strict";
var React = require('react');
import { Widget } from './widget.jsx';

export class ProgramStatusByZoneOverview extends React.Component {

    render() {
        return (
            <Widget keyId={1}>
                <table className="table" id="speaker-fees-table">
                    <thead>
                        <tr>
                            <th>Speaker Fees, Travel...</th>
                            <th>Budgeted Spend</th>
                            <th>Actual Spend</th>
                            <th>Variance</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>Fee For Service</td>
                            <td>250,000</td>
                            <td>150,000</td>
                            <td>-1.5%</td>
                        </tr>
                        <tr>
                            <td>Fee For Service</td>
                            <td>250,000</td>
                            <td>150,000</td>
                            <td>-1.5%</td>
                        </tr>
                        <tr>
                            <td>Fee For Service</td>
                            <td>250,000</td>
                            <td>150,000</td>
                            <td>-1.5%</td>
                        </tr>
                        <tr>
                            <td>Fee For Service</td>
                            <td>250,000</td>
                            <td>150,000</td>
                            <td>-1.5%</td>
                        </tr>
                        <tr>
                            <td>Fee For Service</td>
                            <td>250,000</td>
                            <td>150,000</td>
                            <td>-1.5%</td>
                        </tr>
                    </tbody>
                </table>
            </Widget>
        );
    }
}

1 个答案:

答案 0 :(得分:0)

我想出来了。关键是从我的row.js类开始。我在row.js类上创建了一个click事件,它在行类上设置了expanded = false状态。然后循环遍历每个子项并将此单击处理程序添加为prop。然后将这个道具添加为孩子们的onclick。

export class Widget extends React.Component {
    constructor(props) {
        super(props);
        this.state = {'scale': false, 'class': ''};
        this.hover = this.hover.bind(this);
    }
    hover() {
        if(!this.state.scale){
            this.setState({'scale': true, 'class': 'scaleUp'})
        }else{
            this.setState({'scale': false, 'class': ''})
        }
    }

    render() {
        console.log(this.props.onExpandChange)
        return (
              <div onClick={this.props.onExpandChange} onMouseEnter={this.hover} onMouseLeave={this.hover} className="widget"><WidgetMenu state={this.state.class} />{ this.props.children }</div>
            )
    }
}

"use strict";
var React = require('react');

export class Col extends React.Component {
    render() {
        const childrenWithProps = React.Children.map(this.props.children,
                (child) => React.cloneElement(child, {
                    onExpandChange: this.props.onExpandChange
                })
            );
        return (
            <div  className={"col-" + this.props.size + '-' + this.props.num}>
                {childrenWithProps}
            </div>
        );
    }
}

"use strict";
var React = require('react');

export class Row extends React.Component {
    constructor(props) {
        super(props);
        this.state = {expanded: false}
        this.click = this.click.bind(this);
    }
    click() {
        this.setState({"expanded": !this.state.expanded});
        console.log(this.state.expanded);
    }
    render() {
        const childrenWithProps = React.Children.map(this.props.children,
                (child) => React.cloneElement(child, {
                    onExpandChange: this.click
                })
            );
        return (
            <div className="row">{ childrenWithProps }</div>
        )
    } 
}