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>
        );
      }
    }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个简单的React TodoList组件,包含添加、删除和完成任务的功能,以及任务分组的功能: ```jsx import React, { useState } from "react"; const TodoList = () => { const [inputValue, setInputValue] = useState(""); const [todos, setTodos] = useState([]); const [completedTodos, setCompletedTodos] = useState([]); const [activeTab, setActiveTab] = useState("all"); const handleInputChange = (e) => setInputValue(e.target.value); const handleAddTodo = () => { if (inputValue.trim()) { setTodos([...todos, { id: Date.now(), text: inputValue }]); setInputValue(""); } }; const handleDeleteTodo = (id) => { setTodos(todos.filter((todo) => todo.id !== id)); setCompletedTodos(completedTodos.filter((todo) => todo.id !== id)); }; const handleCompleteTodo = (id) => { const todo = todos.find((todo) => todo.id === id); setTodos(todos.filter((todo) => todo.id !== id)); setCompletedTodos([...completedTodos, todo]); }; const handleTabClick = (tab) => setActiveTab(tab); const getVisibleTodos = () => { switch (activeTab) { case "completed": return completedTodos; case "active": return todos; default: return [...completedTodos, ...todos]; } }; const visibleTodos = getVisibleTodos(); return ( <div> <input value={inputValue} onChange={handleInputChange} /> <button onClick={handleAddTodo}>Add</button> <ul> {visibleTodos.map((todo) => ( <li key={todo.id}> <span style={{ textDecoration: todo.completed ? "line-through" : "" }} onClick={() => todo.completed ? null : handleCompleteTodo(todo.id) } > {todo.text} </span> <button onClick={() => handleDeleteTodo(todo.id)}>X</button> </li> ))} </ul> <div> <button onClick={() => handleTabClick("all")}>All</button> <button onClick={() => handleTabClick("active")}>Active</button> <button onClick={() => handleTabClick("completed")}>Completed</button> </div> </div> ); }; export default TodoList; ``` 这个组件包含一个输入框和添加按钮,用于添加新的任务。任务列表分为两个部分:未完成的任务和已完成的任务。任务可以被删除或标记为已完成。还有三个按钮,用于切换任务列表的显示模式:显示所有任务、只显示未完成的任务、只显示已完成的任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘎嘎油

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值