let ID = 0; // incrementing counter for todo item ids const TodoItem = React.createClass({ mixins: [React.addons.PureRenderMixin], propTypes: { deleteItem: React.PropTypes.func.isRequired, tags: React.PropTypes.arrayOf(React.PropTypes.string.isRequired).isRequired, item: React.PropTypes.shape({ text: React.PropTypes.string.isRequired, id: React.PropTypes.number.isRequired, }).isRequired, }, render() { return ( <div> <button style={{width: 30}} onClick={this.props.deleteItem}>x</button> <span>{this.props.item.text}</span> {this.props.tags.map((tag) => { return <span key={tag} className="tag"> {tag}</span>; })} </div> ); }, }); const Todos = React.createClass({ mixins: [React.addons.LinkedStateMixin], propTypes: { initialItems: React.PropTypes.arrayOf(React.PropTypes.shape({ text: React.PropTypes.string.isRequired, id: React.PropTypes.number.isRequired, }).isRequired).isRequired, }, getInitialState() { return { items: this.props.initialItems, text: '', }; }, addTask(e) { e.preventDefault(); this.setState({ items: [{id: ID++, text: this.state.text}].concat(this.state.items), text: '', }); }, deleteItem(itemId) { this.setState({ items: this.state.items.filter((item) => item.id !== itemId), }); }, render: function() { return ( <div> <h1>My TODOs</h1> <form onSubmit={this.addTask}> <input valueLink={this.linkState('text')} /> <button>Add Task</button> </form> {this.state.items.map((item) => { return ( <TodoItem key={item.id} item={item} tags={['important', 'starred']} deleteItem={this.deleteItem.bind(null, item.id)} /> ); })} </div> ); }, }); // Create a Todos component, initialized with 1000 items. const items = []; for (let i = 0; i < 1000; i++) { items.push({id: ID++, text: 'Todo Item #' + i}); } React.render(<Todos initialItems={items} />, document.body);