React 通过组件提升状态
React Lifting Sate Up Through Components
我无法解决这个问题。我正在编写一个仪表板应用程序以在 React 中使用。我试图让事情变得美好和模块化。我有两个布局 classes "row.js" & "col.js" 它们基本上返回 bootstrap 响应式网格元素,"col-sm-3",等等
我创建了一个小部件 class 和一个可扩展的小部件 class。小部件 class returns 具有某些样式的 div 和可扩展的小部件 class 扩展了小部件 class 并添加了一个点击处理程序以扩展到完整的浏览器宽度。然后我创建自定义小部件 classes 来扩展这些小部件 classes 中的任何一个。这些自定义 classes 将图形或表格等添加到实际组件中。我试图解决的问题是:
在我的 dashboard.jsx 我有:
<Row>
<Col size="sm" num="3">
<SpeakerFees expanded={false}/>
</Col>
<Col size="sm" num="9">
<ProgramStatusByZoneOverview />
</Col>
</Row>
我想单击小部件组件,将其传递给最近的祖先“”并提醒同一行中的其他小部件。根据反应提升状态文档,我们应该提升到最近的祖先……在这种情况下,两个元素向上。这很烦人哈哈
因为仪表板的布局最多只包含大约 10 个小部件,我认为最好是将它们硬编码在 dashboard.jsx 中,而不是使用某种循环。下面是我剩下的 classes.
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'));
和我的小部件 classes:
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>
)
}
}
和小部件-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>
)
}
}
这里是两个彼此相邻的自定义小部件 cols/rows 在 dashboard.jsx 中:
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>
);
}
}
我想通了。关键是从我的 row.js class 开始。我在 row.js class 上创建了一个点击事件,在行 class 上设置了 expanded=false 状态。然后遍历每个 child 并将此点击处理程序添加为道具。然后添加这个prop作为children.
的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>
)
}
}
我无法解决这个问题。我正在编写一个仪表板应用程序以在 React 中使用。我试图让事情变得美好和模块化。我有两个布局 classes "row.js" & "col.js" 它们基本上返回 bootstrap 响应式网格元素,"col-sm-3",等等
我创建了一个小部件 class 和一个可扩展的小部件 class。小部件 class returns 具有某些样式的 div 和可扩展的小部件 class 扩展了小部件 class 并添加了一个点击处理程序以扩展到完整的浏览器宽度。然后我创建自定义小部件 classes 来扩展这些小部件 classes 中的任何一个。这些自定义 classes 将图形或表格等添加到实际组件中。我试图解决的问题是:
在我的 dashboard.jsx 我有:
<Row>
<Col size="sm" num="3">
<SpeakerFees expanded={false}/>
</Col>
<Col size="sm" num="9">
<ProgramStatusByZoneOverview />
</Col>
</Row>
我想单击小部件组件,将其传递给最近的祖先“”并提醒同一行中的其他小部件。根据反应提升状态文档,我们应该提升到最近的祖先……在这种情况下,两个元素向上。这很烦人哈哈
因为仪表板的布局最多只包含大约 10 个小部件,我认为最好是将它们硬编码在 dashboard.jsx 中,而不是使用某种循环。下面是我剩下的 classes.
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'));
和我的小部件 classes:
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>
)
}
}
和小部件-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>
)
}
}
这里是两个彼此相邻的自定义小部件 cols/rows 在 dashboard.jsx 中:
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>
);
}
}
我想通了。关键是从我的 row.js class 开始。我在 row.js class 上创建了一个点击事件,在行 class 上设置了 expanded=false 状态。然后遍历每个 child 并将此点击处理程序添加为道具。然后添加这个prop作为children.
的onclickexport 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>
)
}
}