Todos入门例子(2)

用ES6写React最大的不同就是,组件可以通过继承React.Components来得到,并且初始化state也不需要冗长的getInitalialState,直接在构造函数里操作this.state即可。更优秀的便是...spread扩展操作符,可以让我们省下一堆不必要的代码,这个接下来再说。

App状态state

我们知道React的主流思想就是,所有的state状态和方法都是由父组件控制,然后通过props传递给子组件,形成一个单方向的数据链路,保持各组件的状态一致。所以我们在这个父组件App上,看的东西稍微有点多。一点点来看:

constructor(){ super(); this.db = new LocalDb('React-Todos'); this.state = { todos: this.db.get("todos") || [], isAllChecked: false }; }

在App组件的constructor内,我们先是初始化了我们的localStorage的数据库,放在了this.db上。然后便是初始化了state,分别有两个,一个是todos的列表,一个是所有的todos是否全选的状态。

App方法

// 判断是否所有任务的状态都完成,同步底部的全选框 allChecked() // 添加一个任务,参数是一个todoItem的object addTodo(todoItem) // 改变任务的状态,index是第几个,isDone是状态,isChangeAll是控制全部状态的 changeTodoState(index, isDone, isChangeAll=false) // 参数默认位false // 清空已完成 clearDone() // 删除面板上第几个任务 deleteTodo(index) // react用于渲染的函数 render(){ <div className="panel"> <TodoHeader /> <TodoMain /> <TodoFooter /> </div> }

我们可以从render函数看到整个组件的结构,可以看到其实结构非常简单,就是上中下。上面的TodoHeader自然就是用来输入任务的地方,中间就是展示并操作todo-list的,而底部就是显示数据并提供特殊操作。这里还是要提醒一句,所有标签都必须闭合,即使是非结对的,也要用斜杠闭合上。

render(){ var props = { todoCount: this.state.todos.length || 0, todoDoneCount: (this.state.todos && this.state.todos.filter((todo)=>todo.isDone)).length || 0 }; return ( <div className="panel"> <TodoHeader addTodo={this.addTodo.bind(this)}/> <TodoMain deleteTodo={this.deleteTodo.bind(this)} todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)}/> <TodoFooter isAllChecked={this.state.isAllChecked} clearDone={this.clearDone.bind(this)} {...props} changeTodoState={this.changeTodoState.bind(this)}/> </div> ) }

我们可以看到,其他的方法都是传到子组件上,就不一一详细说如何实现的了。总体的思想就是,方法在父组件定义,通过props传给需要的子组件进行调用传参,最后返回到父组件上执行函数,存储数据、改变state和重新render。方法需要bind(this),不然方法内部的this指向会不正确。

计算需要的数据后,通过props传递到子组件。如果细心的同学应该可以看到像这样的{...props},这就是我之前说过的spread操作符。如果我们没有用这个操作符,就要这样写:

<TodoFooter {...props} /> // spread操作符 <TodoFooter todoCount={props.todoCount} todoDoneCount={props.todoDoneCount} />

最佳的实践就是,当父组件传props给子组件,然后子组件要将props转发给孙子组件的时候,spread操作符简直让人愉悦!可以对一堆麻烦又丑又长的代码可以say goodbye了!

最后我们将整个App渲染到DOM上即可。

React.render(<App/>, document.getElementById("app"));

AppHeader组件

import React from "react"; class TodoHeader extends React.Component { // 绑定键盘回车事件,添加新任务 handlerKeyUp(event){ if(event.keyCode === 13){ let value = event.target.value; if(!value) return false; let newTodoItem = { text: value, isDone: false }; event.target.value = ""; this.props.addTodo(newTodoItem); } } render(){ return ( <div className="panel-header"> <input onKeyUp={this.handlerKeyUp.bind(this)} type="text" placeholder="what's your task ?"/> </div> ) } } export default TodoHeader;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzzssx.html