在Backbone集合中搜索,使用React更新UI

时间:2015-02-15 14:27:51

标签: javascript search backbone.js reactjs

我花时间做一些可能很简单的事情: 我想实现一个搜索栏,理想情况下更新项目列表为你。我的小应用程序使用React和Backbone(用于模型和集合)。

显示列表并不太难,这一切都很完美(我正在使用的mixin基本上允许简单的集合检索):

var List = React.createClass ({

    mixins: [Backbone.React.Component.mixin],

    searchFilter: function () {
        //some filtering code here, not sure how (filter method is only for arrays...)
        }
    }

    getInitialState: function () {
        initialState = this.getCollection().map(function(model) {
            return { 
                    id: model.cid,
                    name: model.get('name'),
                    description: model.get('description')
                    }
        });
        return {
            init: initialState,
            items : []
        }
    },

    componentWillMount: function () {
        this.setState({items: this.state.init})
    },

    render: function(){
        var list = this.state.items.map(function(obj){
            return (
                    <div key={obj.id}>
                        <h2>{obj.name}</h2>
                        <p>{obj.description}</p>
                    </div>      
                )
        });
        return (
            <div className='list'>
            {list}
            </div>
        )
    }
}); 

现在我尝试使用getInitialState方法将主干集合转换为“状态”没有成功,我的想法是通过集合的副本代理,然后可以保存搜索结果。为了清楚起见,我没有在这里展示我的尝试(编辑:我是),有人能引导我采用正确的方法吗?提前谢谢。

2 个答案:

答案 0 :(得分:1)

有很多方法可以实现这一目标,但最简单的(在我看来)是将搜索条件存储在List组件的状态,并使用它来过滤显示集合中的哪些项目。您可以使用filter方法内置的Backbone集合来执行此操作。

var List = React.createClass ({

  mixins: [Backbone.React.Component.mixin],
  getInitialState: function () {
    return {
      nameFilter: ''
    };
  },
  updateSearch: function (event) {
    this.setState({
      nameFilter: event.target.value
    });
  },
  filterItems: function (item) {
    // if we have no filter, pass through
    if (!this.state.nameFilter) return true;
    return item.name.toLowerCase().indexOf(this.state.nameFilter) > -1;
  },
  render: function(){
    var list = this.props.collection
      .filter(this.filterItems.bind(this))
      .map(function(obj){
        return (
          <div key={obj.id}>
            <h2>{obj.name}</h2>
          </div>
        )
    });

    return (
      <div className='list'>
      {list}
        <input onChange={this.updateSearch} type="text" value={this.state.nameFilter}/>
      </div>
    )
  }
});

var collection = new Backbone.Collection([
  {
    name: 'Bob'
  },
  {
    name: 'Bill'
  },
  {
    name: 'James'
  }
]);

React.render(<List collection={collection}/>, document.body);

<强> jsbin

搜索条件可以很容易地从父组件传递下来作为道具,因此搜索输入不必存在于List组件内。

答案 1 :(得分:0)

最终我还找到了一个不同的解决方案(下图),但它涉及将整个集合复制到状态,这可能不是一个好主意......

var List = React.createClass ({

    mixins: [Backbone.React.Component.mixin],

    searchFilter: function () {
        var updatedlist = this.state.init;
        var searchText = this.refs.searchbar.getDOMNode().value
        updatedlist = updatedlist.filter(function (item) {
            return  item.name.toLowerCase().search(
                searchText.toLowerCase()) !== -1
        });
        this.setState({items: updatedlist})
        }
    },

    getInitialState: function () {
        initialState = this.getCollection().map(function(model) {
            return { 
                    id: model.cid,
                    name: model.get('name'),
                    description: model.get('description')
                    }
        });
        return {
            init: initialState,
            items : []
        }
    },

    componentWillMount: function () {
        this.setState({items: this.state.init})
    },

    render: function(){
        var list = this.state.items.map(function(obj){
            return (
                    <div key={obj.id}>
                        <h2>{obj.name}</h2>
                        <p>{obj.description}</p>
                    </div>      
                )
        });
        return (
            <div className='list'>
            <input ref='searchbar' type="text" placeholder="Search" onChange={this.searchFilter}/>
            {list}
            </div>
        )
    }
});