1.Tolist案例(父子傳參實現增刪改)

目錄結構

實現效果:

App.jsx

class App extends Component {
// 狀態在哪裡, 操作狀態的方法就在哪裡
state = {
todos:[
{id:1, name:'吃飯', done: true},
{id:2, name:'睡覺', done: true},
{id:3, name:'打程式碼', done: false},
{id:4, name:'光街', done: true},
]
} // addTodo用於新增一個todo, 接收的引數是todo物件
addTodo = (todoObj) =>{
const {todos} = this.state
const newTodos = [todoObj, ...todos]
this.setState({todos:newTodos})
} // updateTodo用於更新一個todo物件
updateTodo = (id, done) => {
const {todos} = this.state
const newTodos = todos.map(todoObj=>{
if (todoObj.id === id) return {...todoObj, done}
else return todoObj
})
this.setState({todos:newTodos})
} // deleteTodo用於刪除一個todo物件
deleteTodo = (id) => {
const {todos} = this.state
const newTodos = todos.filter((todoObj)=>{
// 將id不是要刪除的todo,重新過濾到一個新陣列
return todoObj.id !== id
})
this.setState({
todos:newTodos
})
}
//checkAllTodo用於全選或者取消全選
checkAllTodo = (done) => {
const {todos} = this.state
const newTodos = todos.map((todoObj)=>{
return {...todoObj, done}
})
this.setState({
todos:newTodos
})
} // 刪除已完成的任務(done為true,刪除已選中的,批量刪除)
clearAllDone = () => {
const {todos} = this.state
const newTodos = todos.filter(todoObj => {
return !todoObj.done
})
this.setState({
todos: newTodos
})
} render() {
const {todos} = this.state
return (
<div className="todo-container">
<div className="todo-wrap">
{/* 子傳父 通過子呼叫父函式 傳參 */}
<Headers addTodo={this.addTodo}/>
{/* 父傳子 傳參 */}
<List todos={todos} updateTodo={this.updateTodo} deleteTodo={this.deleteTodo}/>
<Footer todos={todos} checkAllTodo={this.checkAllTodo} clearAllDone={this.clearAllDone}/>
</div>
</div> )
}
}

Headers.jsx

class Headers extends Component{

    //對接收的props進行:型別、必要性的限制
static propTypes = {
addTodo:PropTypes.func.isRequired
} // 鍵盤迴車事件, 13是回車返回的唯一值
handleKeyUp = (event) => {
const {keyCode, target} = event
if (keyCode !== 13 || target.value.trim() === '') return
const todoObj = {id:nanoid(), name:target.value, done:false}
// 呼叫父元件函式,新增一個todoObj
this.props.addTodo(todoObj)
// 清空輸入框
target.value = ''
// console.log(event.target.value, event.keyCode) } render() {
return (
<div className="todo-header">
{/*監聽鍵盤事件*/}
<input onKeyUp={this.handleKeyUp} type="text" placeholder="請輸入你的任務名稱,按回車鍵確認"/>
</div>
)
}
}

List.jsx

class List extends Component{

    // 對接收的props進行型別、必要性限制
static propTypes = {
todos: PropTypes.array.isRequired,
updateTodo: PropTypes.func.isRequired,
deleteTodo: PropTypes.func.isRequired, } render() {
// 接收從父元件傳來的陣列和方法
const {todos, updateTodo, deleteTodo} = this.props
return (
<ul className="todo-main">
{
todos.map(todo => {
return <Items key={todo.id} {...todo} updateTodo={updateTodo} deleteTodo={deleteTodo}/>
})
} </ul>
)
}
}

Items.jsx

class Items extends Component {

    state = {mouse:false}  // 標識滑鼠移入、移出

    //滑鼠移入、移除的回撥
handleMouse = (flag) =>{
// 函式柯里化
return () =>{
this.setState({mouse:flag})
}
} // 勾選、取消勾選某一個todo的回撥
handleCheck = (id) => {
return (event)=>{
this.props.updateTodo(id, event.target.checked)
// console.log(id, event.target.checked)
} } // 刪除一個todo的回撥
handleDelete = (id) =>{
if (window.confirm('確實刪除?'))
this.props.deleteTodo(id)
} render() {
const {id, name, done} = this.props
const {mouse} = this.state
return (
<li style={{backgroundColor:mouse ? '#ddd': 'white'}} onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
<label>
<input type="checkbox" checked={done} onChange={this.handleCheck(id)}/>
<span>{name}</span>
</label>
<button onClick={()=>this.handleDelete(id)} className="btn btn-danger" style={{display: mouse? 'block': 'none'}}>刪除</button>
</li>
)
}
}

Footer.jsx

class Footer extends Component{

    handleCheckAll = (event) => {
// 是否全選或者取消選中
const done = event.target.checked
this.props.checkAllTodo(done)
} render() {
const {todos} = this.props
// 已完成的個數
const doneCount = todos.reduce((pre, todo)=>pre+(todo.done? 1 : 0),0)
// 總數
const total = todos.length return (
<div className="todo-footer">
<label>
<input onChange={this.handleCheckAll} type="checkbox" checked={doneCount === total && total !== 0}/>
</label>
<span><span>已完成{doneCount}</span> / 全部{total}</span>
<button onClick={this.props.clearAllDone} className="btn btn-danger">清除已完成任務</button>
</div>
)
}
}