上节课我们介绍了如何在脚手架中如何对props
进行限制。这节课我们来学习如何删除一个todo
。
回顾
在开始学习这节课的内容之前我们先俩对上节课的内容来做一个简单的回顾:
prop-types
需要手动安装prop-types
不是必要的,但是加了可以更加规范,方便维护
以上便是上节课的主要要点,其实并没有什么太重要的东西。接下来我们开始这节课的内容。
删除todo
的需求场景
我们之前已经做了添加与完成包括取消完成个这写功能。但是我们想一想如果我一个todo
添加了,但是突然接到通知说这件事不需要做了,那么我们是不是要删除这个todo
?
或者说我们们在规划一天要做的事情,所有的都规划好了,但是中途有事耽搁了一下,然后发现,我们有些事情没有时间做了,那么这些我们是不是也要删掉?
再或者我们一天的事情太多了,而且我们也完成了很多事情,然后每次在看我们的整个清单的时候,完成的和未完成的都夹杂在一起就不够直观。那么我们是不是要删掉这些已完成的事情?这就是我们的需求场景
功能分析
首先我们先来看一下我们的效果图,上面这个清单当我鼠标移入,是不是当前的todo
就高亮了?而且还显示了一个删除按钮。那么我们要删除这个todo
是不是就要给这个删除按钮加上onClick
事件?
那么我们再来分析一下,我们页面上面展示出来的这个todo
的列表是怎么来的?是不是遍历了App
组件的state
的值?那么我们删除按钮的onClick
事件是不是要更改App
组件的state
?
以上就是我们删除todo
功能的一个实现流程好我们来提两个问题:
- 删除按钮在哪个组件中?
- 如修改
state
第一,我们都知道这个删除按钮是Item
组件中的一个button
标签,所以我们是不是要给button
标签添加onClick
事件?
第二我们怎么修改state
?这里问的怎么修改state
可不是在问我们应该怎么样去拿到App
组件的state
然后做修改,这个问题我们已经讲了好几遍了。再老是唠叨这个问题就没有意思了。那么这里的问题是什么意思呢?其实是在问,我们修改的思路,我们根据什么修改?第一我们是不是要拿到这个todo
的id
?只有知道了id
我们才可以去App
的state
中去匹配对应的todo
对象啊。
那么怎么拿?我们onClick
事件是给谁加的?是不是给<button>
?那么这个id
在哪?是不是在props
里?所以说拿到id
简单。那么紧接着是不是就要传给App
组件提供的函数中,因为要改父组件的state
必须要由父组件提供入口函数啊。然后在入口函数接收到了id
之后是不是就要作出相应的处理来修改state
?
以上就是我们删除todo
功能的实现思路。
实现
我们上面已经分析了思路了,那么是不是就简单了啊?我们来看一下代码
export default class Item extends Component { state = { mouse: false }; render() { const { todo } = this.props; const { mouse } = this.state; return ( ... <button onClick={this.handleDelete(todo.id)} ...>删除</button> ... ) } handleCheck = id => {...}; handleDelete = id => { return () => { console.log(id); }; }; handleMouse = flag => {...}; }
一些目前不需要关注的代码我就省略了,我们但看<button>
,我们给绑定了onClick
事件,设置了回调是handleDelete
方法,并且从props
中拿到了当前todo
的id
传给了handleDelete
方法。再来看看这个方法,我们只需要接收id
参数,但是我们在<button>
中是不是直接调用了这个方法?那么我们就要返回一个函数。那么我们来看一下效果:
我们点击按钮是不是就能成功打印出id
了啊?但是我们的目的又不是打印id
,那么我们是不是要在App
组件中来提供一个给Item
组件来修改state
的入口函数?我们来看一下:
export default class App extends Component { state = { todos: [] }; add = dataObj => {...}; update = (id, done) => {...} deleteTodo = id => { const { todos } = this.state; const newTodos = todos.filter(todo => todo.id !== id); this.setState({ todos: newTodos }); } render() { const { todos } = this.state; return ( ... <List todos={todos} update={this.update} deleteTodo={this.deleteTodo} /> ... ) } }
我们来看首先我们来看deleteTodo
方法,这个就是用来删除的方法。首先我们是不是要先获取我们之前的todos
?那么我们怎么通过一个id
来从数组中删掉对应的todo
对象呢?如果这里大家们,没有在第一时间想到数组的filter
方法,那么赶紧回去复习原生js
中的数组那一块的内容。
filter
方法是要接收一个执行器函数来做处理的,那么这个函数怎么写?我们要过滤掉某个id
的元素,是不是直接返回那些和指定id
不等的元素就可以了?
好了,现在数组也处理好了,啊么是不是就修改state
就行了,那么这个方法就算是完成了,接下来我们要把这个方法提供给Item
组件使用,但是Item
不是App
的子组件啊,这个我们上节课是不是就已经说过了?Item
是List
的子组件,而List
是App
的子组件,那么就把方法传给List
然后在List
中结构赋值拿到函数再传给Item
。我们来看一下代码
// List 组件 export default class List extends Component { render() { const { todos, update, deleteTodo } = this.props; return ( <ul className="todo-list"> {todos.map(todo => <Item ... deleteTodo={deleteTodo} />)} </ul> ) } } // Item 组件 export default class Item extends Component { state = { mouse: false }; render() {...} handleCheck = id => {...}; handleDelete = id => { return () => { const {deleteTodo} = this.props; deleteTodo(id); }; }; handleMouse = flag => {...}; }
List
组件中拿到deleteTodo
函数并将该函数传给了Item
组件,在Item
的handleDelete
方法中直接调用deleteTodo
方法即可。那么我们来看一下效果是不是符合我们预期:
之前我们是这些todo
那么我们删除来看一下:
删除之后便是只剩下这两个todo
。所以至此我们的删除todo
功能就已经完成了。
可能有些人会问,为什么我们之前都是update
和add
这次的方法用了deleteTodo
?因为如果我们直接写delete
作为方法名的话,在List
中解构赋值那一步就会报错,为什么?因为delete
是一个关键字,用于删除对象中的指定属性,问出这个问题的也要去复习一下原生js
的基础语法了。
弹窗确认
现在有一个问题如果我不小心误删了怎么办?我们可没有回收站功能啊,那么我们加一个弹窗提醒呗,就在Item
组件的handleDelete
方法中加一个是不是就可以了?但是我们能用alert
吗?不能啊,alert
只有一个确定按钮啊,这不是绑架嘛,让别人只能删除。那么我们原生js
中是不是有一个confirm
啊?点击确定就返回true
否则返回false
。
但是有意思的来了报错了,react
不认识这个confirm
,那么怎么办呢?我们需要告诉react
我们用的是window.confirm
。那么我们来看一下
export default class Item extends Component { state = { mouse: false }; render() {...} handleCheck = id => {...}; handleDelete = id => { return () => { if (!window.confirm("Are you sure you want to delete?")) return; const {deleteTodo} = this.props; deleteTodo(id); }; }; handleMouse = flag => {...}; }
我们添加了这一行,如果confirm
返回的是false
,我们就不做任何操作,否则删除。来看一下效果:
点击确定删除喝茶todo
,那么如果我们点击取消,睡觉todo
没有被删除。
总结
- 数组的
filter
方法用来根据某些条件完成过滤效果 delete
是一个关键字,不能直接拿来做方法名confirm
再使用时要指定window.confirm
Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.
Link of this article:https://work.lynchow.com/article/todolist_delete_todo/