React初学者:如图,点击勾选时,会报错。请问各位大神啥原因?

image.png

image.png

image.png

TodoList.jsx

import React, { Component } from 'react';
import './TodoList.css';
import Header from './Header';
import ListItem from './ListItem';
import Footer from './Footer';
export default class TodoList extends Component {
    state = {
        lists: [{name: 'fff',id: '25631', checked: false}]
    }

    addTodo = (list) => {
        this.setState({lists: [list, ...this.state.lists]});
    }

    handleCheck = (id, checked) => {
        const {lists} = this.state
        const newLists = lists.map(item => {
            if (id === item.id) {
                item.checked = checked
            }
            return item;
        })
        console.log(newLists);
        this.setState({lists: newLists});
    }

    handleDelete = (id) => {
        this.setState({lists: this.state.lists.filter(item => item.id !== id)});
    }

    handleCheckAll = (flag) => {
        this.setState({lists: this.state.lists.map(item => {
                item.checked = flag
                return item;
            })
        });
    }

    handleClearAllDone = () => {
        this.setState({lists: this.state.lists.filter(item => !item.checked) });
    }


    render() {
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    <Header addTodo={this.addTodo}/>
                    <ListItem lists={this.state.lists} handleCheck={this.handleCheck} handleDelete={this.handleDelete}/>
                    <Footer lists={this.state.lists} handleCheckAll={this.handleCheckAll} handleClearAllDone={this.handleClearAllDone}/>
                </div>
            </div>
        )
    }
}
复制代码

Header.jsx

import React, { Component } from 'react';

import PropTypes from 'prop-types';
import {nanoid} from 'nanoid';


export default class Header extends Component {
    static propTypes = {
        addTodo: PropTypes.func.isRequired
    }
    
    handleKeyUp = (e) => {
        if (e.keyCode === 13) {
            const value = e.target.value;
            e.target.value = '';
            return this.props.addTodo({name: value, id: nanoid(), checked: false});
        }
    }
    
    render() {
        return (
            <div className="todo-header">
				<input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
			</div>
        )
    }
}
复制代码

ListItem.jsx

import React, { Component } from 'react'
import PropTypes from 'prop-types'


export default class ListItem extends Component {
    static propTypes = {
        lists: PropTypes.array.isRequired,
        handleDelete: PropTypes.func.isRequired,
        handleCheck: PropTypes.func.isRequired,
    }

    handleDelete(id) {
        console.log(id);
        this.props.handleDelete(id)
    }

    handleCheck = (id) => {
        return (event) => {
            this.props.handleCheck(id, event.target.checked)
        }
    }

    render() {
        const {lists} = this.props;
        console.log(lists);
        return (
            <div className={lists.length ? 'todo-main' : ''}>
                {
                    lists.map(item => (
                            <div className="li" key={item.id}>
                                <label>
                                    <input type="checkbox" checked={item.checked} onChange={this.handleCheck(item.id)}/>
                                    <span>{item.name}</span>
                                </label>
                                <button onClick={()=> this.handleDelete(item.id) } className="btn btn-danger" >删除</button>
                            </div>
                    ))
                }
            </div>
        )
    }
}

复制代码

Footer.jsx

import PropTypes from 'prop-types'

export default class Footer extends Component {
    static propTypes = {
        lists: PropTypes.array.isRequired,
        handleCheckAll: PropTypes.func.isRequired,
        handleClearAllDone: PropTypes.func.isRequired,
    }

    handleCheckAll = (e) => {
        return () => {
            this.props.handleCheckAll(e.target.checked)
        }
    }

    handleClearAllDone = () => {
        this.props.handleClearAllDone()
    }

    render() {
        const { lists } = this.props
        const total = lists.length;
        const checkedTotal = lists.filter(item => item.checked); 
        return (
            <div className="todo-footer">
                <div style={{float: 'left'}}>
                    <label>
                        <input type="checkbox" onChange={this.handleCheckAll}
                         checked={total.length === checkedTotal.length && total.length ? true : false}/>
                    </label>
                    <span>
                        <span>已完成{checkedTotal}</span> / 全部{total}
                    </span>
                </div>
                <button onClick={this.handleClearAllDone} className="btn btn-danger">清除已完成任务</button>
            </div>
        )
    }
}

复制代码

css


.btn {
  display: inline-block;
  padding: 4px 12px;
  margin-bottom: 0;
  font-size: 14px;
  line-height: 20px;
  text-align: center;
  vertical-align: middle;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
  border-radius: 4px;
}

.btn-danger {
  color: #fff;
  background-color: #da4f49;
  border: 1px solid #bd362f;
}

.btn-danger:hover {
  color: #fff;
  background-color: #bd362f;
}

.btn:focus {
  outline: none;
}

.todo-container {
  width: 600px;
  margin: 0 auto;
  background: #fff;
}
.todo-container .todo-wrap {
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 5px;
}

/*header*/
.todo-header input {
    width: 560px;
    height: 28px;
    font-size: 14px;
    border: 1px solid #ccc;
    border-radius: 4px;
    padding: 4px 7px;
  }
  
  .todo-header input:focus {
    outline: none;
    border-color: rgba(82, 168, 236, 0.8);
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6);
  }
  /*main*/
.todo-main {
    margin-top: 20px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0;
  }
  
  .todo-empty {
    height: 40px;
    line-height: 40px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding-left: 5px;
    margin-top: 10px;
  }
  /*item*/
.li {
    list-style: none;
    height: 36px;
    line-height: 36px;
    padding: 0 5px;
    border-bottom: 1px solid #ddd;
  }
  
  .li label {
    float: left;
    cursor: pointer;
  }
  
  .li label, .li input {
    vertical-align: middle;
    margin-right: 6px;
    position: relative;
    top: -1px;
  }
  
  .li button {
    float: right;
    display: none;
    margin-top: 7px;
  }

  .li:hover{
    background-color: rgb(235, 230, 230);
  }
  .li:hover button{
    display: inline-block;
  }
  
  .li:before {
    content: initial;
  }
  
  .li:last-child {
    border-bottom: none;
  }
/*footer*/
.todo-footer {
    height: 40px;
    line-height: 40px;
    padding-left: 6px;
    margin-top: 5px;
  }
  
  .todo-footer label {
    display: inline-block;
    margin-right: 20px;
    cursor: pointer;
  }
  
  .todo-footer label input {
    position: relative;
    top: -1px;
    vertical-align: middle;
    margin-right: 5px;
  }
  
  .todo-footer button {
    float: right;
    margin-top: 5px;
  }
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享