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

Search in Backbone Collections, Updating UI with React

本文关键字:使用 React 更新 UI 搜索 Backbone Collections      更新时间:2023-11-05

我正在花时间做一些可能很简单的事情:我想实现一个搜索栏,最好是在键入时更新项目列表。我的小应用程序使用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方法首先将主干集合转换为"state",但没有成功,我的想法是通过集合的副本进行代理,然后可以保存搜索结果。为了清晰起见,我不会在这里展示我的尝试(编辑:是的,我是),有人能引导我采取正确的方法吗?提前谢谢。

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

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组件中。

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

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>
        )
    }
});