TodoList小练习
todoList案例相关知识点
-
拆分组件、实现静态组件,注意: className、 style的写润Ⅰ
-
动态初始化列表,如何确定将数据放在哪个组件的state中?
- 某个组件使用:放在自身的state中
- 某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升>
-
关于父子之间通信:
- 【父组件】给【子组件】传递数据:通过props传递
- 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
-
注意defaultchecked 和 checked的区别,类似的还有: defaultValue和 value
-
状态在哪里,操作状态的方法就在哪里
文件夹结构
因为关注的是react的学习,所以懒得写less文件修饰了
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nR9T0ypk-1652255785368)(C:\Users\12274\AppData\Roaming\Typora\typora-user-images\image-20220506233638382.png)]
App.js
import Header from './components/Header';
import List from './components/List'
import Footer from './components/Footer';
import './App.less';
import React, {Component} from 'react';
class App extends Component {
state = {
todos:[
{id:'001',name:'吃饭',done:true},
{id:'002',name:'啪啪',done:true},
{id:'003',name:'睡觉',done:false},
]
}
addTodo = (val) =>{
console.log(val)
const {todos} = this.state
const newTodos = [val,...todos]
this.setState({
todos:newTodos
})
}
changeTodo = (id,done)=>{
const {todos} = this.state
const newTodos = todos.map((item) =>{
if(item.id === id) return {...item,done}
else return item
})
this.setState({
todos:newTodos
})
}
deleteTodo = (id)=>{
const {todos} = this.state
//删除指定id的todo
const newTodos = todos.filter((item)=>{
return item.id !== id
})
this.setState({
todos:newTodos
})
}
checkAllTodo = (state)=>{
const {todos} = this.state
const newTodos = todos.map((item)=>{
return {...item,done:state}
})
this.setState({
todos:newTodos
})
}
clearAllDone = ()=>{
const {todos} = this.state
const newTodos = todos.filter((item)=>{
return item.done === false
})
this.setState({
todos:newTodos
})
}
render(){
const {todos} = this.state
return (
<div className="App">
<Header addTodo={this.addTodo}/>
<List changeTodo={this.changeTodo} todos={todos} deleteTodo={this.deleteTodo}/>
<Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone}/>
</div>
);
}
}
export default App;
Header.jsx
import React,{Component} from "react";
import PropTypes from 'prop-types'
export default class Header extends Component {
static propTypes = {
addTodo:PropTypes.func.isRequired
}
handleKeyUp = (event) =>{
const {keyCode,target} = event
if(keyCode !== 13) return;
console.log(target.value)
if(target.value.trim() === true) alert('不能为空')
let todoObj = {
id: Date.now(),
name:target.value,
done:false
}
this.props.addTodo(todoObj)
}
render(){
return(
<div>
<input type="text" onKeyUp={this.handleKeyUp} />
</div>
)
}
}
List.jsx
import React,{Component} from "react";
import Item from "../item";
import PropTypes from 'prop-types'
export default class List extends Component {
static propTypes = {
changeTodo:PropTypes.func.isRequired,
}
render(){
const {todos,changeTodo,deleteTodo} = this.props
console.log(changeTodo)
return(
<div>
<ul>
{
todos.map((item)=>{
return <Item key={item.id} {...item} changeTodo={changeTodo} deleteTodo={deleteTodo}/>
})
}
</ul>
</div>
)
}
}
Item.jsx
import React,{Component} from "react";
export default class Item extends Component {
handleCheck = (id) =>{
return (event)=>{
console.log(this.props)
this.props.changeTodo(id,event.target.checked)
}
}
handleDelete = (id) =>{
this.props.deleteTodo(id)
}
render(){
const {id,name,done} = this.props
return(
<li>
<label htmlFor="">
<input onChange={this.handleCheck(id)} checked={done} type="checkbox"/>
<span>{name}</span>
</label>
<button onClick={()=>{this.handleDelete(id)}}>删除</button>
</li>
)
}
}
Footer.jsx
import React, { Component } from "react";
export default class Footer extends Component {
handleCheckAll = (event)=>{
this.props.checkAllTodo(event.target.checked)
}
handleDeleteAll = ()=>{
this.props.clearAllDone()
}
render(){
const {todos} = this.props
//已完成的个数
const doneCount = todos.filter(item=>{
return item.done === true
}).length
//总数
const total = todos.length
return(
<div>
<label htmlFor="">
<input type="checkbox" onChange={this.handleCheckAll} checked={doneCount === total&&total !== 0 ? true : false} name="" id="" />
</label>
<span>
<span>已完成{doneCount}</span> / 全部{total}
</span>
<button onClick={this.handleDeleteAll}>清楚已完成任务</button>
</div>
)
}
}