源码地址
- Ui层分析
- 列表展示区域和输入区域和按钮区域
- 列表输入区域包括一个全选的状态按钮
- 列表展示区域包括选择完成,删除任务
- 按钮区域筛选list todo状态按钮
- 功能分析
- 新增事件
- 删除事件 功能可以实现,但是有个报错
- 标记完成事件 功能实现,但是在遍历上我觉得可以优化
- 筛选事件
- 全选事件
- 踩坑知识点
- 向数组中新增list todo时,不要使用push,因为push返回的是数组的新长度。应该用concat
- 给todo添加自己的id时,key字段不能作为props传递,如果想使用key的值,应该用一个新的字段传递
- 要更加理解可控组件
- 删除一个todo时, todo:todo.splice() 返回的是被删除的值,但是splice会改变原数组。要注意函数的返回值
- 当我们通过props传值给state,如果父组件改变了props,子组件却并不会更新。因为组件的更新只涉及两种
- setState明确的显示改变
- props直接接受父组件的props
- 筛选功能时,三种选择,我选择的是第三种,因为第一种我认为是一种浪费?并且再改变todo的某些属性时,总觉得需要同时更新两个数组。第二种方法最初我是这样使用的,但是后来我发现,其实isShow的值其实是和isDone,以及currentState的值相关联起来的。
- 用两个数组,第一个存储全部的todo,第二个存储需要被渲染出来的todo
- 用一个数组,为每一个todo添加一个isShow的属性,
- 使用isDone和currentState来得到isShow的值
const isShow = (currentState === 2 || Boolean(parseInt(currentState, 10)) === !isDone);
- 全选功能,要考虑多种情况,我添加了一个state属性,switchStateAll来表示,全选按钮的状态
- 在三种状态下,点击全选按钮,会实时改变,这个可以通过isDone和全选按钮的状态来改变每个todo的isDone属性
todo.isDone = newSwitchStateAll;
- 当在全选完成的时候新增任务时,全选完成状态应该消失
- 当改变单个todo的isDone属性的时候,全选状态应该同步,比如:(总结来说,其实是第三种,单个按钮状态改变,全选按钮状态改变)
- 如果单个全部选择,全选按钮自动亮起
- 如果单个全部不选中,全选按钮自动熄灭
- 单个按钮改变状态,全选按钮改变状态
思路:用newSwitchStateAll来决定最终的全选框状态,用tempIsDone作为一个暂存值,用来对比, todos数组中前后todo的isDone的值。思考在什么情况下,newSwitchStateAll才会为真呢?只有在每一个todo的isDone状态都为真的时候才可能。所以如果前后todo的值不同,那newSwitchStateAll肯定为false,就算前后todo的值相同,那他们的值也必须为true,newSwitchStateAll才会为true,其余情况下newSwitchStateAll应该都为false
let newSwitchStateAll;
let tempIsDone;
if (this.state.todos.length === 1) {
newSwitchStateAll = todo.isDone;
} else if (typeof tempIsDone === 'undefined') {
tempIsDone = todo.isDone;
newSwitchStateAll = true;
} else if (!(tempIsDone === todo.isDone && tempIsDone === true)) {
newSwitchStateAll = false;
}
- 思考题
- 什么时候使用state什么时候使用props?怎么说,可以使用props的尽量使用props,组件只做ui层的渲染,这样便于以后用redux管理状态,也便于组件的复用
- 总结:最难得就是当初我以为最简单,差点不想做的全选按钮了。全选需要考虑的情况较多,可能是因为我的构思有问题,在全选上的逻辑处理比较复杂,如果使用Vue来做同样的todolist可能,通过Vue的计算属性,逻辑会简单很多。因为react处处是组件,而Vue可能一个todolist才会是一个完整的组件,只需要通过一个data就可以管理全部的数据。