React手写一个TodoList案例

二、TodoList案例

1. todoList案例相关知识点

  • 拆分组件、实现静态组件,注意: className、 style的写法
    在这里插入图片描述

  • 动态初始化列表,如何确定将数据放在哪个组件的state中?

    • 某个组件使用:放在其自身的state中
    • 某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
  • 关于父子之间通信:

    • 【父组件】给【子组件】传递数据:通过props传递
    • 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数
    • 注意defaultchecked 和 checked的区别,类似的还有: defaultvalue和value
    • 状态在哪里,操作状态的方法就在哪里

2. 代码:

  • App.jsx

    export default class App extends Component {
      // 初始化状态
      state = {
        todos: [
          { id: "001", name: "吃饭", done: true },
          { id: "002", name: "睡觉", done: true },
          { id: "003", name: "敲代码", done: false },
        ],
      };
    
      // 添加一个todo
      addTodo = (todoObj) => {
        this.setState({
          todos: [todoObj, ...this.state.todos],
        });
      };
    
      // 修改todo的勾选
      updateTodo = (id, state) => {
        this.setState({
          todos: this.state.todos.map((todo) => {
            // 方式一
            // if (todo.id === id) todo.done = state;
            // return todo;
            //方式二
            if (todo.id === id) return { ...todo, done: state };
            return todo;
          }),
        });
      };
    
      // 删除一个todo
      deleteTodo = (id) => {
        this.setState({
          todos: this.state.todos.filter((x) => x.id !== id),
        });
      };
    
      // 反选
      checkAllTodo = (done) => {
        this.setState({
          todos: this.state.todos.map((todo) => {
            return { ...todo, done };
          }),
        });
      };
    
      // 清除所有已完成
      clearDone = () => {
        this.setState({
          todos: this.state.todos.filter((x) => !x.done),
        });
      };
    
      render() {
        const { todos } = this.state;
        return (
          <div className="todo-container">
            <div className="todo-wrap">
              <Header addTodo={this.addTodo} />
              <List
                todos={todos}
                updateTodo={this.updateTodo}
                deleteTodo={this.deleteTodo}
              />
              <Footer
                todos={todos}
                checkAllTodo={this.checkAllTodo}
                clearDone={this.clearDone}
              />
            </div>
          </div>
        );
      }
    }
    
  • List.jsx

    render() {
        const { todos, updateTodo, deleteTodo } = this.props;
        return (
            <ul className="todo-main">
                {todos.map((todo) => {
                    return (
                        <Item
                            {...todo}
                            key={todo.id}
                            updateTodo={updateTodo}
                            deleteTodo={deleteTodo}
                        />
                    );
                })}
            </ul>
        );
    }
    
  • Item.jsx

    export default class Item extends Component {
      state = {
        mouse: false, //鼠标移除移入的标识
      };
    
      // 鼠标移出移入的回调
      handleMouse = (flag) => {
        return (event) => {
          this.setState({
            mouse: flag,
          });
        };
      };
    
      // 勾选、取消勾选的回调
      handleCheck = (id) => {
        return (event) => {
          this.props.updateTodo(id, event.target.checked);
        };
      };
    
      // 删除一个todo
      handleDelete(id) {
        if (window.confirm("确定删除吗?")) {
          this.props.deleteTodo(id);
        }
      }
    
      render() {
        const { id, name, done } = this.props;
        return (
          <li
            onMouseEnter={this.handleMouse(true)}
            onMouseLeave={this.handleMouse(false)}
            style={{ backgroundColor: this.state.mouse ? "#ddd" : "white" }}
          >
            <label>
              <input
                type="checkbox"
                checked={done}
                onChange={this.handleCheck(id)}
              />
              <span>{name}</span>
            </label>
            <button
              className="btn btn-danger"
              onClick={() => this.handleDelete(id)}
              style={{ display: this.state.mouse ? "block" : "none" }}
            >
              删除
            </button>
          </li>
        );
      }
    }
    
  • Header.jsx

    export default class Header extends Component {
      // 对接收的props进行:类型、必要性的限制
      static propTypes = {
        addTodo: PropTypes.func.isRequired,
      };
    
      // 处理按键
      handleKeyUp = (event) => {
        // 解构赋值
        const { addTodo } = this.props;
        const { key, target } = event;
        // 判断是否按下回车
        if (key !== "Enter") return;
        if (target.value.trim() === "") return alert("输入不能为空!");
        addTodo({ id: nanoid(), name: target.value, done: false });
        target.value = "";
      };
    
      render() {
        return (
          <div className="todo-header">
            <input
              onKeyUp={this.handleKeyUp}
              type="text"
              placeholder="请输入你的任务名称,按回车键确认"
            />
          </div>
        );
      }
    }
    
  • Footer.jsx

    export default class Footer extends Component {
      // 全选
      handleCheckAll = (event) => {
        this.props.checkAllTodo(event.target.checked);
      };
    
      // 清除已完成
      handleClearDone = () => {
        this.props.clearDone();
      };
    
      render() {
        const { todos } = this.props;
        // 计算已完成个数
        let doneCount = todos.reduce((pre, todo) => {
          return todo.done ? pre + 1 : pre;
        }, 0);
        // 总数
        let total = todos.reduce((pre) => {
          return pre + 1;
        }, 0);
    
        return (
          <div className="todo-footer">
            <label>
              <input
                type="checkbox"
                checked={doneCount === total && total !== 0}
                onChange={(event) => this.handleCheckAll(event)}
              />
            </label>
            <span>
              <span>已完成{doneCount}</span> / 全部{total}
            </span>
            <button onClick={this.handleClearDone} className="btn btn-danger">
              清除已完成任务
            </button>
          </div>
        );
      }
    }
    
posted @ 2022-12-16 09:37  你就是星光  阅读(56)  评论(0)    收藏  举报