Created by Ping-Wen (Mark) Hsu
2015/11/10 for ReactJS Waterloo
If you app structure looks like this:
I'm sorry about that
If looks like this:
Fine, you can stay :-)
Example
View
//view.js
views.ItemView = Backbone.View.extend({
events:{
'click .toggle': 'toggleCompleted',
},
initialize:function{
this.listenTo(this.model, 'change', this.render);
},
render:function(){
var itemHTML = _.template(item_html)({
item: this.model
});
this.$el.html(itemHTML);
},
toggleCompleted:function(event){
this.model.toggle();
}
});
Template
<input class="toggle" type="checkbox" <%= item.get("completed") ? 'checked': '' %>>
<label><%= item.get("title") %></label></label>
Step 1: Make a HTML render machine
class Item extends React.Component{
render(){
const { item } = this.props;
return (
<div className="view>
<input className="toggle" type="checkbox" item.get("completed") ? 'checked': '' />
<label>item.get("name")</label>
<button className="destroy"></button>
</div>
);
}
}
<input class="toggle" type="checkbox" <%= item.get("completed") ? 'checked': '' %>>
<label><%= item.get("title") %></label></label>
//Component.render()
const { item } = this.props;
return (
<div className="view">
<input className="toggle" type="checkbox" item.get("completed") ? 'checked': '' />
<label>item.get("name")</label>
<button className="destroy"></button>
</div>
);
Then modify view render function
//view.js
views.ItemView = Backbone.View.extend({
render:function(){
//before
var itemHTML = _.template(item_html)({
item: this.model
});
this.$el.html(itemHTMLitemHTML);
//after
React.render(
<Item item={this.model} />,
this.$el
);
},
});
Step 2: Write events handler
2-1: Create a click handler
class Item extends React.Component{
handleToggle(){
this.props.toggleCompleted();
}
render(){
const { item } = this.props;
return (
<div className="view>
<input className="toggle"
type="checkbox"
item.get("completed") ? 'checked': ''
onClick={this.handleToggle.bind(this)}/>
<label>item.get("name")</label>
<button className="destroy"></button>
</div>
);
}
}
2-2: Pass the view function into the component
//view.js
views.ItemView = Backbone.View.extend({
// events:{
// 'click .toggle': 'toggleCompleted',
// },
initialize:function{
this.listenTo(this.model, 'change', this.render);
},
render:function(){
React.render(
<Item item={this.model} toggleCompleted={toggleCompleted} />,
this.$el
);
},
toggleCompleted:function(event){
this.model.toggle();
}
});
Step 3: Replace Backbone View
A question needs to be answer:
Is the model only be used by the current view/component?
If yes, keep using model as a prop
class Item extends React.Component{
handleToggle(){
this.model.toggle();
}
render(){
const { item } = this.props;
return (
<div className="view>
<input className="toggle"
type="checkbox"
item.get("completed") ? 'checked': ''
onClick={this.handleToggle.bind(this)}/>
<label>item.get("name")</label>
<button className="destroy"></button>
</div>
);
}
}
If no, use states instead
class Item extends React.Component{
constructor(props){
super(props);
this.state = {
model: this.props.model,
};
}
handleToggle(){
this.state.model.toggle();
this.setState({model:this.model});
}
render(){
const item = this.state.model;
return (
<div className="view>
<input className="toggle"
type="checkbox"
item.get("completed") ? 'checked': ''
onClick={this.handleToggle.bind(this)}/>
<label>item.get("name")</label>
<button className="destroy"></button>
</div>
);
}
}
//ListView.js
views.ListView = Backbone.View.extend({
render:function(){
var Items = this.collections.map(function(item){
return (
<Item item={item}
//Pass function if ListView is in charge of data mutating
toggleCompleted={toggleCompleted}
key={item.get("id")}/>
);
});
React.render(
Items,
this.$el
);
},
});
Step 4: Apply internal Flux by features
Can I still use third-party libraries?
You can use those:
You can't use those: