react 脚手架 todos 练手小项目分享
注意红框中的文件,其中 01_脚手架自带文件 和 02_x 不用理会,忽略就好

// App.js
import React, { Component } from 'react'
import Header from './components/Header'
import Footer from './components/Footer'
import List from './components/List'
export default class App extends Component {
    constructor(props){
        super(props);
        this.state = {
            todos:[
                {
                    id:"001",
                    todo:"睡觉",
                    done:true
                },
                {
                    id:"002",
                    todo:"吃饭",
                    done:true
                },
                {
                    id:"003",
                    todo:"看书",
                    done:false
                }
            ]
        }
    }
    updateTodos = () => {
       return (todoObj) => {
            const todos = [todoObj,...this.state.todos];
            this.setState({todos});
       }
    }
    handleChange = (id,done) => {
       const {todos} = this.state;
       const newTodos = todos.map(todo => {
           if(todo.id === id) return {...todo,done:done}
           else return todo
       })
       this.setState({todos:newTodos})
    }
    handleDelete = (id) => {
        const {todos} = this.state;
        const newTodos = todos.filter((todo) => {
            return todo.id !== id;
        })
        this.setState({todos:newTodos});
    }
    handleCheckedAll = (done) => {
        const {todos} = this.state;
        const newTodos = todos.map(todo => {
            return {...todo,done}
        })
        this.setState({todos:newTodos})
    }
    handleDeleteAll = () => {
        const {todos} = this.state;
        const newTodos = todos.filter(todo => {
            return todo.done === false;
        })
        this.setState({todos:newTodos})
    }
    render() {
        const {todos} = this.state;
        return (
            <div className="container">
                <Header updateTodos={this.updateTodos()}/>
                <List todos={todos} handleChange = {this.handleChange} handleDelete = {this.handleDelete}/>
                <Footer todos={todos} handleCheckedAll = {this.handleCheckedAll} handleDeleteAll = {this.handleDeleteAll}/>
            </div>
        )
    }
}
复制代码
// Header.jsx
import React, { Component } from 'react'
import {nanoid} from 'nanoid'
export default class Header extends Component {
    addItem = (event) => {
        let {updateTodos} = this.props;
        let todoObj = {
            id:nanoid(),
            todo:event.target.value,
            done:false
        }
        if(event.keyCode === 13){
            updateTodos(todoObj);
            event.target.value = "";
        }
    }
    render() {
        return (
            <div className="header">
                <input type="text" placeholder="请输入内容,按回车键确认" onKeyUp={this.addItem}/>
            </div>
        )
    }
}
复制代码
// List.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
export default class List extends Component {
    static ropTypes = {
        handleChange:PropTypes.func.isRequired,
        todos:PropTypes.array.isRequired
    }
    render() {
        const {todos,handleChange,handleDelete} = this.props;
        return (
            <ul className="list-container">
                {todos.map(todo=>{
                    return <Item {...todo} key={todo.id} handleChange={handleChange} handleDelete = {handleDelete}/>
                })}
            </ul>
        )
    }
}
复制代码
// Item.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export default class Item extends Component {
    static propTypes = {
        handleChange:PropTypes.func.isRequired
    }
    deleteItem = (id) => {
        console.log("被删除的id是",id);
        if(window.confirm("确定删除吗?")){
            this.props.handleDelete(id);
        }
    }
    handleChange = (id) => {
        const {handleChange} = this.props;
        return (event) => {
            handleChange(id,event.target.checked);
        }
    }
    render() {
        const {id,todo,done} = this.props;
        return (
            <li className="list-item">
                <input type="checkbox" checked={done} onChange={this.handleChange(id)} /> 
                <span>{todo}</span> 
                <button onClick={()=>{this.deleteItem(id)}}>删除</button> {/* 这里没有使用高阶函数,就直接写成了这样的 */}
            </li>
        )
    }
}
复制代码
// Footer.jsx
import React, { Component } from 'react'
export default class Footer extends Component {
    deleteAll = ()=>{
        this.props.handleDeleteAll();
    }
    checkedAll = (event) => {
        this.props.handleCheckedAll(event.target.checked);
    }
    render() {
        const {todos} = this.props;
        const total = todos.length;
        const doneCount = todos.reduce((pre,current)=>{
            return pre + (current.done === true ? 1 : 0);
        },0)
        return (
            <div className="footer">
                <input type="checkbox" checked={doneCount === total && total !== 0 ? true:false} onChange={this.checkedAll}/>
                <span>{doneCount}完成/全部{total}</span>
                <button onClick={this.deleteAll}>清除已完成项目</button>
            </div>
        )
    }
}
复制代码
最终的成品

© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
    





















![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)