过滤React Js中的Todo列表

我是React的新手(我以前习惯使用Angular),我目前正在根据类别选择过滤我的Todo列表应用程序。

我从http://todomvc.com/examples/react/#/克隆了Todo列表应用程序。 我添加了一个“类别”输入,它可以工作,但是现在我尝试在显示列表后按类别进行过滤。

我目前没有任何类别搜索function,我正在寻找一些指导,从哪里开始。 我将发布下面的代码,但如果你想要克隆它,这里是我的repo的链接: https : //github.com/aenser/todo-react

app.jsx

var app = app || {}; (function () { 'use strict'; app.ALL_TODOS = 'all'; app.ACTIVE_TODOS = 'active'; app.COMPLETED_TODOS = 'completed'; var TodoFooter = app.TodoFooter; var TodoItem = app.TodoItem; var ENTER_KEY = 13; var TodoApp = React.createClass({ getInitialState: function () { return { nowShowing: app.ALL_TODOS, editing: null, newTodo: '', newCategory: '' }; }, componentDidMount: function () { var setState = this.setState; var router = Router({ '/': setState.bind(this, {nowShowing: app.ALL_TODOS}), '/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}), '/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS}) }); router.init('/'); }, handleChange: function (event) { this.setState({newTodo: event.target.value}); }, handleCategoryChange: function (event) { this.setState({newCategory: event.target.value}); }, handleNewTodoKeyDown: function (event) { if (event.keyCode !== ENTER_KEY) { return; } event.preventDefault(); var val = this.state.newTodo.trim(); var cat = this.state.newCategory.trim(); if (val, cat) { this.props.model.addTodo(val, cat); this.setState({newTodo: '', newCategory: ''}); } }, toggleAll: function (event) { var checked = event.target.checked; this.props.model.toggleAll(checked); }, toggle: function (todoToToggle) { this.props.model.toggle(todoToToggle); }, destroy: function (todo) { this.props.model.destroy(todo); }, edit: function (todo) { this.setState({editing: todo.id}); }, save: function (todoToSave, text, cat) { this.props.model.save(todoToSave, text, cat); this.setState({editing: null}); }, cancel: function () { this.setState({editing: null}); }, clearCompleted: function () { this.props.model.clearCompleted(); }, render: function () { var footer; var main; var todos = this.props.model.todos; var shownTodos = todos.filter(function (todo) { switch (this.state.nowShowing) { case app.ACTIVE_TODOS: return !todo.completed; case app.COMPLETED_TODOS: return todo.completed; default: return true; } }, this); var todoItems = shownTodos.map(function (todo) { return (  ); }, this); var activeTodoCount = todos.reduce(function (accum, todo) { return todo.completed ? accum : accum + 1; }, 0); var completedCount = todos.length - activeTodoCount; if (activeTodoCount || completedCount) { footer = ; } if (todos.length) { main = ( 
    {todoItems}
); } return (

todos

Select a Category Urgent Soon Anytime
{main} {footer}
); } }); var model = new app.TodoModel('react-todos'); function render() { React.render( , document.getElementsByClassName('todoapp')[0] ); } model.subscribe(render); render(); })();

todoModel.js

 var app = app || {}; (function () { 'use strict'; var Utils = app.Utils; // Generic "model" object. You can use whatever // framework you want. For this application it // may not even be worth separating this logic // out, but we do this to demonstrate one way to // separate out parts of your application. app.TodoModel = function (key) { this.key = key; this.todos = Utils.store(key); this.onChanges = []; }; app.TodoModel.prototype.subscribe = function (onChange) { this.onChanges.push(onChange); }; app.TodoModel.prototype.inform = function () { Utils.store(this.key, this.todos); this.onChanges.forEach(function (cb) { cb(); }); }; app.TodoModel.prototype.addTodo = function (title, category) { this.todos = this.todos.concat({ id: Utils.uuid(), title: title, category: category, completed: false }); this.inform(); }; app.TodoModel.prototype.toggleAll = function (checked) { // Note: it's usually better to use immutable data structures since they're // easier to reason about and React works very well with them. That's why // we use map() and filter() everywhere instead of mutating the array or // todo items themselves. this.todos = this.todos.map(function (todo) { return Utils.extend({}, todo, {completed: checked}); }); this.inform(); }; app.TodoModel.prototype.filterAll = function () { this.todos = this.todos.map(function (todo) { return Utils.extend({}, todo); }); this.inform(); }; app.TodoModel.prototype.toggle = function (todoToToggle) { this.todos = this.todos.map(function (todo) { return todo !== todoToToggle ? todo : Utils.extend({}, todo, {completed: !todo.completed}); }); this.inform(); }; app.TodoModel.prototype.destroy = function (todo) { this.todos = this.todos.filter(function (candidate) { return candidate !== todo; }); this.inform(); }; app.TodoModel.prototype.save = function (todoToSave, text, cat) { this.todos = this.todos.map(function (todo) { return todo !== todoToSave ? todo : Utils.extend({}, todo, {title: text}, {category: cat}); }); this.inform(); }; app.TodoModel.prototype.clearCompleted = function () { this.todos = this.todos.filter(function (todo) { return !todo.completed; }); this.inform(); }; })(); 

todoItem.jsx

 var app = app || {}; (function () { 'use strict'; var ESCAPE_KEY = 27; var ENTER_KEY = 13; app.TodoItem = React.createClass({ handleSubmit: function (event) { var val = this.state.editText.trim(); var cat = this.state.editCategoryText.trim(); if (val || cat) { this.props.onSave(val, cat); this.setState({editText: this.props.todo.title, editCategoryText: this.props.todo.category}); } else { this.props.onDestroy(); } }, handleEdit: function (event) { this.props.onEdit(); this.setState({editText: this.props.todo.title, editCategoryText: this.props.todo.category}); }, handleKeyDown: function (event) { if (event.which === ESCAPE_KEY) { this.setState({editText: this.props.todo.title}); this.props.onCancel(event); } else if (event.which === ENTER_KEY) { this.handleSubmit(event); } }, handleChange: function (event) { if (this.props.editing) { this.setState({editText: event.target.value}); } }, handleCategoryChange: function (event) { if (this.props.editing) { this.setState({editCategoryText: event.target.value}); } }, getInitialState: function () { return {editText: this.props.todo.title, editCategoryText: this.props.todo.category}; }, /** * This is a completely optional performance enhancement that you can * implement on any React component. If you were to delete this method * the app would still work correctly (and still be very performant!), we * just use it as an example of how little code it takes to get an order * of magnitude performance improvement. */ shouldComponentUpdate: function (nextProps, nextState) { return ( nextProps.todo !== this.props.todo || nextProps.editing !== this.props.editing || nextState.editText !== this.state.editText || nextState.editCategoryText !== this.state.editCategoryText ); }, /** * Safely manipulate the DOM after updating the state when invoking * `this.props.onEdit()` in the `handleEdit` method above. * For more info refer to notes at https://facebook.github.io/react/docs/component-api.html#setstate * and https://facebook.github.io/react/docs/component-specs.html#updating-componentdidupdate */ componentDidUpdate: function (prevProps) { if (!prevProps.editing && this.props.editing) { var node = React.findDOMNode(this.refs.editField); node.focus(); node.setSelectionRange(node.value.length, node.value.length); } }, render: function () { return ( 
  • Urgent Soon Anytime
  • ); } }); })();

    感谢您抽出宝贵时间帮助我了解如何根据类别选择过滤搜索。

    你的界面有点令人困惑,因为你似乎使用相同的输入选择来为todos和过滤分配类别,我会在答案的最后得到它,但是现在,我只是使用了类别选择器来输入数据和按类别过滤。

    你的问题的答案非常简单。 您只需按类别和完成状态进行过滤。 像这样:

      var shownTodos = todos.filter(function(todo) { return(todo.category === this.state.newCategory); }, this).filter(function (todo) { switch (this.state.nowShowing) { case app.ACTIVE_TODOS: return !todo.completed; case app.COMPLETED_TODOS: return todo.completed; default: return true; } }, this); 

    我会在底部添加一些按钮,用于当前显示的分类。 您还可以像nowShowing一样为类别添加一组新的状态,如nowShowingCategory 。 按钮会将其设置为类别的3个值,您可以在上面的filter中使用该变量,而不是我的示例中的newCategory