strategy of React integration

Using Backbone as Example

Created by Ping-Wen (Mark) Hsu

2015/11/10 for ReactJS Waterloo

Down arrow

If you app structure looks like this:

Down arrow

I'm sorry about that

If looks like this:

Down arrow

Fine, you can stay :-)

Down arrow
Down arrow
Down arrow
Down arrow

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
        );
    },
});
                            
                        
Down arrow

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();
    }
});
                        
                    
Down arrow

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
  • If no, use states instead

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
    ); 
  },
});
                          
                      
Down arrow

Step 4: Apply internal Flux by features

Down arrow
Down arrow
Down arrow
Down arrow

Can I still use third-party libraries?

You can use those:

  • Moment.js
  • wysiwyg.js
  • socket.io
  • validate.js
  • jQuery(Ajax, Events)

You can't use those:

  • jQuery UI (use React-DnD instead)
  • Hammer.js (use React-DnD instead)
  • jQuery (DOM Manipulation)

Demo time

Integration steps review

  1. Make a HTML render machine
  2. Write events handler
  3. Replace Backbone View
  4. Apply internal Flux by features

Questions?

Thank you