todolist案例是一个类似于笔记本的一个小案例,能做到添加输入内容到列表中,指定删除对应的列表数据,前提基础要会react,掌握react中的事件和获取dom元素的值,以及状态的获取和修改。案例中的样式是最简单的一种,学会了之后,大家可以按照自己想要的设计风格修改,也可以扩展内容,如统计列表中展示的条数等。案例中需要注意的是深拷贝问题
todolist案例视频
一、思路
1、获取输入框中的内容。这里有好几种方式,我这里采取的是ref方式来获取react之ref_夏*想想的博客-CSDN博客
2、点击add添加输入框内容至列表中react——事件绑定_夏*想想的博客-CSDN博客,成功添加后清空输入框中的内容
3、点击del,对应删除列表中的数据
二、实践
代码中已经详细的注释解析了,就不在这里赘述了
import React, { Component } from 'react'
import './todolist.css'
// 简单得todolist
export default class ToDoList extends Component {
/*
todolist实现思路:
1、获取输入框中的内容。这里有好几种方式,我这里采取的是ref方式来获取
2、点击add添加输入框内容至列表中,成功添加后清空输入框中的内容
3、点击del,对应删除列表中的数据
*/
// 1、获取input中输入的值
myRef = React.createRef()
// 2、存储输入后点击add的值
state = {
// 准备一个数组用于存放输入框中的内容
list: [{ id: 1, text: '11' }, { id: 2, text: '21' }],
}
// add事件
addFn = () => {
// 3、每次点击后追加到list列表中
var newList = [...this.state.list]
newList.push({
id: Math.random() * 1000000,//随机id
text: this.myRef.current.value//ref绑定获取到单前输入的内容
})
// 修改追加后的数组
this.setState({
list: newList
})
// 4、清空输入框内容
this.myRef.current.value = ""
}
// del事件
delFn = (index) => {
var newList = this.state.list.concat()
// 通过传入的index,来指定删除
newList.splice(index, 1)
// 修改删除后的数组
this.setState({
list: newList
})
}
render() {
return (
<div className='todolist'>
<div className='form'>
<input ref={this.myRef} />
<button onClick={this.addFn}>add</button>
</div>
<ul>
{/* 通过map循环来生成对应的列表 */}
{
this.state.list.map((item, index) => (
<li key={item.id}>
<p>{item.text}</p>
<button onClick={this.delFn.bind(this, index)}>del</button>
</li>
))
}
</ul>
</div>
)
}
}
三、思考
修改状态时的setState是异步的,我们对数组进行操作时,大部分数组方法会修改到原数组,因此建议先将数组深拷贝一次,修改后再重新赋值。深拷贝的方法有:
(一)解构数组中的每一项,再重新赋值,如案例中的...
(二)序列化
JSON.parse(JSON.stringify(数组)),有局限性,如对象里有函数, undefind, data对象此方法不行
import React, { Component } from 'react'
export default class App9 extends Component {
state = {
arr: ["张飞", "赵云", "刘备"]
}
render() {
return (
<div>
<ul>
{
this.state.arr.map((item, index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
<button onClick={this.addFn.bind(this)}>追加一项到arr的最后</button>
<button onClick={this.chanFn.bind(this)}>修改arr的最后一项</button>
</div>
)
}
// 追加一项到arr的最后
// 修改state的方式只能是setState
// 数组的push方法会修改原数组
// this.state.arr.push() 会造成直接修改了state中的arr
// 修改数组,不能直接修改this.state.arr
addFn(){
// 如果我声明一个变量,等于this.state.arr,并且让这个变量和this.state.arr完全脱离关系[深拷贝]
let newArr = JSON.parse(JSON.stringify(this.state.arr));
// 往newArr中push一项
newArr.push('关羽');
// 把最新的newArr赋值给arr
this.setState({
arr: newArr
})
}
// 修改最后一项
chanFn(){
// 如果我声明一个变量,等于this.state.arr,并且让这个变量和this.state.arr完全脱离关系[深拷贝]
let newArr = JSON.parse(JSON.stringify(this.state.arr));
//修改最后一项
newArr.splice(3,1,'如花');
// 把最新的newArr赋值给arr
this.setState({
arr: newArr
})
}
}
(三)递归
比较费手和脑子
const obj = {
name: 'zs',
family: {
father: 'zs',
mother: 'ls'
},
hobby: ['打游戏', '喝奶茶', '熬夜']
}
const newObj = {}
function deepClone(target, old) {
for (const key in old) {
if (old[key] instanceof Array) {
// 判断是否为数组
// TODO...
// deepCopy 深拷贝; 深复制; 深层复制;
target[key] = []
deepClone(target[key], old[key])
} else if (old[key] instanceof Object) {
// 判断是否为对象
// TODO...
target[key] = []
deepClone(target[key], old[key])
} else {
// TODO...
target[key] = old[key]
}
}
}
deepClone(newObj, obj)
// 用来检验是否深拷贝成功
obj.family.father = '王五'
obj.hobby[0] = '睡觉'
console.log(obj);
console.log(newObj);
(四)借助插件lodash
// 引入lodash
const _ = require('lodash')
const obj = {
name: 'zs',
family: {
father: 'zs',
mother: 'ls'
},
hobby: ['打游戏', '喝奶茶', '熬夜']
}
// TODO...
// 使用lodash
const newObj = _.cloneDeep(obj)
// 下面代码不要动, 用来检验是否深拷贝成功
obj.family.father = '王五'
obj.hobby[0] = '睡觉'
console.log(obj);
console.log(newObj);