react todolist 3_List

功能:1.输入框输入事项,点击add,list增加一条,输入框清空并且聚焦;

2.点击当前checkbox,勾选文字为已完成,取消勾选文字为未完成;

父组件TodoList.js

分成了三个子组件

TodoHeader,TodoInput,List

 

import React, { Component } from 'react';
import{TodoInput,TodoHeader,List} from './index.js'

class TodoList extends Component {
constructor(){
super()
this.state={
title2:"今日事今日毕",
todos:[{
id:1,
title:"吃饭",
isComleted:true
},
{
id:2,
title:"学习",
isComleted:true
},
{
id:3,
title:"睡觉",
isComleted:false
},
]
}
}
render() {
return (
<div className="App">
<TodoHeader title='待办事项'>
{this.state.title2}
</TodoHeader>
<TodoInput btnText='add' addTodo={this.addTodo}/>
<List todo={this.state.todos} onisComletedChange={this.onisComletedChange}></List>
</div>
);
}

addTodo=(todoTitle)=>{
console.log('子元素传值',todoTitle)
//注意不能用push这样写,因为push返回的是数组的长度
// this.setState({
// todos:this.state.todos.concat({
// id:Math.random(),
// title:todoTitle,
// isComleted:false
// })
// })
//用push这样写
// const newTodos = [...this.state.todos]
// newTodos.push({
// id:Math.random(),
// title:todoTitle,
// isComleted:false
// })
// this.setState({
// todos:newTodos
// })

//第三种新值添加进数组的方法
const newlist = {
id:Math.random(),
title:todoTitle,
isComleted:false
}
this.setState({
todos:[...this.state.todos,newlist]
})
}


//点击checkbox取反
onisComletedChange=(id)=>{
console.log(id)
const data = this.state.todos.map(item=>{
if(item.id===id){
item.isComleted=!item.isComleted
}
return item
})
this.setState({
todos:data
})
}

}

export default TodoList

TodoHeader.js

import React, { Component } from 'react';

export default class TodoHeader extends Component {
render() {
console.log(this.props) //{title: "待办事项", children: "今日事今日毕"}
return (
<div>
<h1>{this.props.title}</h1>
<p>{this.props.children}</p>
</div>
);
}
}

TodoInput.js

import React, { Component,createRef } from 'react';

export default class TodoInput extends Component {
constructor(){
super()
this.state={
inputValue:''
}
this.handleAdd = this.handleAdd.bind(this)
this.handleKeyUp = this.handleKeyUp.bind(this)
//定义createRef
this.inputDom = createRef()
}
render() {
return (
<div>
<input type="text"
value={this.state.inputValue}
onChange={this.handleInput.bind(this)}
onKeyUp={this.handleKeyUp}
ref={this.inputDom}
/>
<button onClick={this.handleAdd}>{this.props.btnText}</button>
</div>
);
}

//点击添加从state中获取最新值 输入框聚焦this.inputDom.current.focus()
handleAdd(){
if(this.state.inputValue ===''){
return
}else{
//接收父组件addTodo事件,并将input参数传递给父元素
this.props.addTodo(this.state.inputValue)
console.log('inputDom',this.inputDom)
this.setState({
inputValue:""
},()=>{
this.inputDom.current.focus()
})
}
}

//获取input的值,并交给state
handleInput(e){
// console.log(e.currentTarget.value)
this.setState({
inputValue:e.currentTarget.value
})
}

//回车输入
handleKeyUp(e){
// console.log(e.keyCode)
if(e.keyCode ===13){
this.handleAdd()

this.setState({
inputValue:""
})
}

}
}

List.js

import React, { Component } from 'react';
//引入类型检查插件
import PropTypes from 'prop-types'

export default class List extends Component {
//父元素类型验证 验证todo是否是array,以及内部各项的数据类型验证
static propTypes = {
todo:PropTypes.arrayOf(PropTypes.shape({
id:PropTypes.number.isRequired,
title:PropTypes.string.isRequired,
isComleted:PropTypes.bool.isRequired,
})).isRequired
}
render() {
console.log(this.props.todo) //父组件传来的todo
let todo = this.props.todo
return (
<div>
{
todo.map(item=>{
return <div key={item.id}>{item.title}
<input
style={{marginLeft:'30px'}}
type="checkbox"
checked={item.isComleted} //默认true的选中
onChange={this.handleBoxChange.bind(this,item.id)} //当前点击的id传给onChange事件
/>
<span>{item.isComleted?'已完成':'未完成'}</span>
</div>
})
}
</div>
);
}
handleBoxChange(id){
// console.log(id)
this.props.onisComletedChange(id) //接收父元素的事件并传值

}
}