strategy of React intergration – Using Backbone as Example



strategy of React intergration – Using Backbone as Example

0 0


react-integration-strategy


On Github sq0032 / react-integration-strategy

strategy of React integration

Using Backbone as Example

Created by Ping-Wen (Mark) Hsu

2015/11/10 for ReactJS Waterloo

The reason I choose Backbone is because this is what I'm currently working on. I tried AngularJs, but it's not making live easier. Just want to share how I did the change.
The frontend technologies have changed so fast, every new technology did solve some problem and increase development speed. However, all the frameworks have there own specific way to do things, it's expensive to move from one to another.

If you app structure looks like this:

I'm sorry about that

React or my strategy neither a medicine that cures all the diseases.

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

                            
<!-- Template -->
<div class="view">
    <input class="toggle" type="checkbox" <%= item.get("completed") ? 'checked': '' %>>
    <label><%= item.get("title") %></label></label>
    <button class="destroy"></button>
</div>
                        
                    

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>
    );
  }
}
                            
                        
                            
<!-- Template -->
<div class="view">
    <input class="toggle" type="checkbox" <%= item.get("completed") ? 'checked': '' %>>
    <label><%= item.get("title") %></label></label>
    <button class="destroy"></button>
</div>
                            
                        
                            
//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

This slide has fragments which are also stepped through in the notes window.

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>
    );
  }
}
                            
                        
Create a click handler, and call the function that pass in as a prop.

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();
    }
});
                        
                    
Now you start taking benefit from React by simplifing event transmition procesure. Some people would add/remove classname here which you don't need it with React. Just put the logic into the component's render function.

Step 3: Replace Backbone View

This part is tricky one, cuz here is the place you need to make a desision.

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
Adoption of single source of truth begins.

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>
    );
  }
}                            
                            
                        
The mutation happens in a parent component

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>
    );
  }
}                            
                            
                        
This model is the single source of truth.
                          
//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
    ); 
  },
});
                          
                      
The more you climb up the tree, the more you simplify your app.

Step 4: Apply internal Flux by features

This part is tricky one, cuz here is the place you need to make a desision.

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

Make a HTML render machine Write events handler Replace Backbone View Apply internal Flux by features

Questions?

Thank you

strategy of React integration Using Backbone as Example Created by Ping-Wen (Mark) Hsu 2015/11/10 for ReactJS Waterloo The reason I choose Backbone is because this is what I'm currently working on. I tried AngularJs, but it's not making live easier. Just want to share how I did the change.