reactjs


React Lifting Sate Up Through Components


I'm having trouble wrapping my head around this. Im writing a dashboard app to play around with in react. I'm trying to keep things nice and modular. I have two layout classes "row.js" & "col.js" They essentially are returning bootstrap responsive grid element, "col-sm-3", etc.
I have created a widget class and a widget-expandable class. The widget class returns a div with some styles and the widget-expandable class extends the widget class and adds a click handler to expand to the full browser width. Then I create custom widget classes that extend either of these widget classes. These custom classes add graphs or tables, etc to the actual component. The problem im trying to fix is:
In my dashboard.jsx I have:
<Row>
<Col size="sm" num="3">
<SpeakerFees expanded={false}/>
</Col>
<Col size="sm" num="9">
<ProgramStatusByZoneOverview />
</Col>
</Row>
I want to click on the widget component, pass it to the nearest ancestor, "" and alert the other widget(s) in the same row. According to the react lifting state docs, we're supposed to lift to the nearest ancestor..in this case two elements up. This is annoying lol
Because the layout of the dashboard will only contain about a max of 10 total widgets, i figured it was best i just hardcode those out in dashboard.jsx instead of having some kind of loop. Below are the rest of my 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'));
and my widget 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>
)
}
}
and 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>
)
}
}
and here are the two custom widgets that would be next to each other is cols/rows in the 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>
);
}
}
and
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>
);
}
}
I figured this out. The key was starting in my row.js class. I created a click event on the row.js class that set a state of expanded=false on the row class. Then looped over each child and added this click handler as a prop. Then added this prop as the onclick of the children.
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>
)
}
}

Related Links

Cannot read property “charAt” of undefined
SPClientPeoplePicker is undefined using SPF'x
React: To put simple logic in Container or Presentational component?
ReactJs - How to get updated state while inside a thunk promise
Syntax error on comonent proxy
TypeScript custom declaration files for untyped npm modules
React native ex-navigation chnaging routers
React and Authorization using an API
electron not allowed to load local resource
How to use jsx-control-statements in reactjs?
Leaflet with Webpack: error in css-loader
React - Where should I load async data?
Infinite componentDidUpdate() calls with react-router
How to ignore .d.ts file inside npm package?
Using goBack function from react-router-redux
Can I create alias routes using react router?

Categories

HOME
qlikview
postgresql
stata
alasql
service
grpc
microcontroller
liquibase
ebay-api
assign
terminal
powerquery
jshell
multipartform-data
schema
jquery-select2
android-webview
doctrine2
revit-api
rtc
wkhtmltopdf
websharper
email-attachments
virtualenv
drush
expo
react-select
css-float
vivado-hls
airbnb
google-drive-android-api
ppp
chartist.js
priority-queue
uibarbuttonitem
checkmarx
recreate
restler
zimbra
http-proxy
tunnel
outlook-2010
jibx
libconfig
jquery-inputmask
gem-fury
uitextview
definition
smooth-streaming
nshttpurlresponse
scrapinghub
html-entities
amazon-fire-tv
encoder
ack
synchronized
jsfl
google-cloud-shell
cloudconvert
e4
riemann
dynamic-linking
webmatrix
liferay-ide
try-catch-finally
timex
scanf
msiexec
therubyracer
spring-social-twitter
nimbus
avaudiorecorder
custom-build-step
calc
code-translation
video-embedding
opendolphin
bioconductor
recode
gitk
redquerybuilder
edgar
updating
tooltwist
callfire
litedb
photogrammetry
drools-guvnor
jsonmodel
frisby.js
illegalargumentexception
xmlserializer
yosemite
system.net
javacompiler
pyalgotrade
django-tests
rda
image-preloader
new-operator
slimscroll
object-oriented-database
autofilter
playing-cards
kademlia
asp.net-4.0
ntdll
configurationsection
derived-class
jquery-1.8
xcode4.6.3
reflexil
clgeocoder
windows-xp-embedded
youtube.net-api
jexcelapi
xhtmlrenderer
quazip
fxcopcmd
table-valued-parameters
jquery-attributes
linq-to-mysql
numerical-computing
content-delivery-network
tracd

Resources

Encrypt Message