Replacing State with Props
So first we need to reset some stuff.
..
var ContentToggle = React.createClass({
getInitialState: function () {
return {
showDetails: false
}
},
..
})
..
var App = React.createClass({
getInitialSate () {
return {
toggleAll: true
}
},
toggleAll () {
console.log('uh what now')
},
render () {
return (
<div>
<h1>Props v. State</h1>
<button onClick={this.toggleAll}>Toggle All</button>
<div style={{margin: '10px 0'}}>
<ContentToggle isOpen={this.state.toggleStates.jerk} summary="Jerk Chicken">
<p>It was delicious</p>
</ContentToggle>
<ContentToggle isOpen={this.state.toggleStates.thai} summary="Thai">
<p>It was probably good too</p>
</ContentToggle>
</div>
</div>
)
}
});
Continue from here
..
var ContentToggle = React.createClass({
// 2. ---- Can remove the state
// ---- getInitialState: function () {
// ---- return {
// ---- showDetails: false
// ---- }
// ---- },
// 3. ++++ add props:
propTypes : {
isOpen: React.PropTypes.bool
},
..
renderDetails () {
var showStuff = this.state.showDetails;
if (showStuff) {
return this.props.children;
} else {
return null;
}
},
toggle () {
// still uses state, will need to be changed later
this.setState({
showDetails: !this.state.showDetails
});
}
render () {
var summaryClassName = "ContentToggle__Summary";
// 4. ++-- change if(this.state.showDetails)
// use props instead of states
if(this.props.isOpen){
details = this.props.children;
summaryClassName += " ContentToggle__Summary--open";
}
return (
<div className="ContentToggle">
<div onClick={this.toggle} className="summaryClassName">{this.props.summary}</div>
<div className="ContentToggle__Details">{this.renderDetails()}</div>
</div>
);
}
});
})
..
var App = React.createClass({
getInitialSate () {
return {
toggleAll: true,
// 1. ++++
toggleSates: {
jerk: true,
thai: false
}
}
},
toggleAll () {
console.log('uh what now')
},
render () {
return (
<div>
<h1>Props v. State</h1>
<button onClick={this.toggleAll}>Toggle All</button>
<div style={{margin: '10px 0'}}>
<ContentToggle isOpen={this.state.toggleStates.jerk} summary="Jerk Chicken">
<p>It was delicious</p>
</ContentToggle>
<ContentToggle isOpen={this.state.toggleStates.thai} summary="Thai">
<p>It was probably good too</p>
</ContentToggle>
</div>
</div>
)
}
});
Now, on the first run the app works according to the settings in getInitialState
But now the individual components click handlers don't seem to work. need to change the
toggle
handler above:
// 2. ++++ add proptype:
propTypes : {
isOpen: React.PropTypes.bool.isRequired,
onToggle: React.PropTypes.func.isRequired
},
toggle () {
// 1. ++-- change
this.props.onToggle();
},
// 3. ++++ update maybefocus to use props
maybeFocus () {
if (this.props.isOpen) {
this.refs.details.getDOMNode().focus();
}
},
Normally all state has been removed. But still need to update ContentToggle
attributes
<ContentToggle
// 1. ++++ add onToggle
onToggle={this.handleToggle.bind(this, 'jerk');
isOpen={this.state.toggleStates.jerk} summary="Jerk Chicken">
<p>It was delicious</p>
</ContentToggle>
Does the same for the other ContentToggle
. Add
handlToggle
(just above the render ()
)
handleToggle(id) {
console.log(id);
}
So now, the parent owns the state.
..
var ContentToggle = React.createClass({
propTypes : {
isOpen: React.PropTypes.bool.isRequired,
onToggle: React.PropTypes.func.isRequired
},
toggle () {
this.props.onToggle();
},
maybeFocus () {
if (this.props.isOpen) {
this.refs.details.getDOMNode().focus();
}
},
..
renderDetails () {
var showStuff = this.state.showDetails;
if (showStuff) {
return this.props.children;
} else {
return null;
}
},
toggle () {
this.setState({
showDetails: !this.state.showDetails
});
},
handleToggle(id) {
// 1. ++++ set the handler
var { toggleStates } = this.state;
// set to the opposite
toggleStates[id] = !toggleStates[id];
this.setState({ toggleStates })
// same as { toggleStates: toggleStates }
}
render () {
var summaryClassName = "ContentToggle__Summary";
if(this.props.isOpen){
details = this.props.children;
summaryClassName += " ContentToggle__Summary--open";
}
return (
<div className="ContentToggle">
<div onClick={this.toggle} className="summaryClassName">{this.props.summary}</div>
<div className="ContentToggle__Details">{this.renderDetails()}</div>
</div>
);
}
});
})
..
var App = React.createClass({
getInitialSate () {
return {
toggleAll: true,
toggleSates: {
jerk: true,
thai: false
}
}
},
toggleAll () {
console.log('uh what now')
},
render () {
return (
<div>
<h1>Props v. State</h1>
<button onClick={this.toggleAll}>Toggle All</button>
<div style={{margin: '10px 0'}}>
<ContentToggle
onToggle={this.handleToggle.bind(this, 'jerk');
isOpen={this.state.toggleStates.jerk} summary="Jerk Chicken">
<p>It was delicious</p>
</ContentToggle>
<ContentToggle
onToggle={this.handleToggle.bind(this, 'thai');
isOpen={this.state.toggleStates.thai} summary="Thai">
<p>It was probably good too</p>
</ContentToggle>
</div>
</div>
)
}
});
You push your state upwards in the application. The cursor pattern. When you move your state all the way to the top – the cursor. This is the OM pattern in ClojureScript.
David Nolan ClojureScript library - uses React with ClojureScript. Use one big unmutable object. If it changes, the whole app re-renders.
CircleCI - shows a video. Can have snapshots of states.
The state moves upwards and your app is made from pure components.
Another pattern is to go all the way to the top, then to the site in stores.(Flux pattern)
The above code works, but the focus (tab focus) doesn't move to the content.Need to add
componentDidUpdate
life cycle method (component re-renders and updates):
toggle () { .. },
componentDidUpdate () {
this.maybeFocus();
}
maybeFocus: function { .. },
handleToggle(id) {.. }
Now the focus moves to the child