ToDoList案例 (React实现)

该文展示了如何在React应用中拆分组件,实现静态组件和动态化初始列表。通过实例讲解了状态的初始化和管理,包括如何决定数据存储位置,以及组件间通信的方法,如props传递。同时,文章提供了添加、更新、删除Todo列表的完整代码示例,涉及事件处理和状态更新。
摘要由CSDN通过智能技术生成

知识点:

  1. 拆分组件、实现静态组件,注意className、style的写法,className = "XXX" style={{style={{fontSize:'50px'}}
  2. 动态化初始列表,如何确定将数据放在哪个组件的state中  1、某个组件使用:放在自身的state里面    2、某些组件使用,放在公共的父组件state里面
  3. 关于父子之间通信   1、【父组件】给【子组件】:通过props传递 2、【子组件】给【父组件】通过props传递,要求父先给子一个函数
  4. 状态在哪里,操作状态的方法就在哪里

App.jsx

import React, { Component } from "react";
import Footer from "./components/Footer";
import Header from "./components/Header";
import List from "./components/List";
export default class App extends Component {
  // 初始化状态
  state = {
    todos: [
      { id: "001", name: "吃饭", done: false },
      { id: "002", name: "睡觉", done: true },
      { id: "003", name: "敲代码", done: true },
    ],
  };
  // 添加Todo数值
  addTodo = (todoObj) => {
    const { todos } = this.state;
    const newTodos = [todoObj, ...todos];
    this.setState({ todos: newTodos });
  };
  // 勾选单选框 取消和选中
  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 = (id) => {
    const { todos } = this.state;
    const newTodos = todos.filter((todoObj) => {
      return todoObj.id !== id;
    });
    this.setState({ todos: newTodos });
  };
  // 全选
  checkAllTodo = (done) => {
    const {todos} = this.state
    const newTodos = todos.map((todoObj) => {
      return {...todoObj,done}
    });
    this.setState({todos:newTodos})
  }

  deleteAllTodo = () => {
    const { todos } = this.state;
    const newTodos = todos.filter((todoObj) => {
      return todoObj.done === false
    });
    this.setState({ todos: newTodos });
  }
  
  

  render() {
    const { todos } = this.state;
    return (
      <div>
        <Header addTodo={this.addTodo} />
        <List
          todos={todos}
          updateTodo={this.updateTodo}
          deleteTodo={this.deleteTodo}
        />
        <Footer todos={todos} deleteAllTodo={this.deleteAllTodo} checkAllTodo={this.checkAllTodo}/>
      </div>
    );
  }
}

Footer.jsx

import React, { Component } from "react";
import "./index.css";
export default class index extends Component {
  handleCheckAll = (e) => {
    this.props.checkAllTodo(e.target.checked);
  };
  handleDelAll = () => {
    this.props.deleteAllTodo()
  }
  
  render() {
    const { todos } = this.props;
    // 已完成个数
    // 方法1
    // const doneCount = todos.filter((todoObj)=>{
    //   return todoObj.done == true
    // })
    // 方法2
    const doneCount = todos.reduce((pre, todos) => {
      return pre + (todos.done ? 1 : 0);
    }, 0);

    // 总数
    const total = todos.length;
    return (
      <div className="todo-footer">
        <label>
          {/*注意不能使用defaultChecked,这个只能在初始化的时候执行一次,并且如果使用checkede就必须添加onChange*/}
          <input
            type="checkbox"
            onChange={this.handleCheckAll}
            checked={doneCount === total && total !== 0 ? true : false}
          />
        </label>
        <span>
          <span>已完成{doneCount}</span> / 全部{total}
        </span>
        <button onClick={this.handleDelAll} className="btn btn-danger">清除已完成任务</button>
      </div>
    );
  }
}

Header.jsx

import React, { Component } from "react";
import { nanoid } from "nanoid";
import PropTypes from "prop-types";
import "./index.css";
export default class index extends Component {
  // 对接收的参数进行限制
  static propTypes = {
    addTodo: PropTypes.func.isRequired,
  };
  handleKeyUp = (e) => {
    const { target } = e;
    if (e.keyCode !== 13) return;
    if (target.value.trim() === "") {
      alert("输入为空");
      return;
    }
    const todoObj = { id: nanoid(), name: target.value, done: false };
    this.props.addTodo(todoObj);
    target.value = "";
  };
  render() {
    return (
      <div className="todo-header">
        <input
          onKeyUp={this.handleKeyUp}
          type="text"
          placeholder="按住回车确定"
        />
      </div>
    );
  }
}

Item.jsx

import React, { Component } from "react";
import "./index.css";
import PropTypes from "prop-types";
export default class index extends Component {
  static propTypes = {
    updateTodo: PropTypes.func.isRequired,
    deleteTodo: PropTypes.func.isRequired,
  };
  // 初始化状态
  state = { mouse: false };
  // 移入和移出样式改变
  handleMouse = (flag) => {
    return () => {
      this.setState({ mouse: flag });
    };
  };
  // 勾选单选框 取消和选中
  handleCheck = (id, done) => {
    return (e) => {
      const { target } = e;
      this.props.updateTodo(id, target.checked);
    };
  };
  // 删除
  handleDelete = (id, name) => {
    return () => {
      if (window.confirm(`您确认要删除 ${name} 吗?`)) {
        this.props.deleteTodo(id);
      }
      else{
        console.log('用户点击了取消');
      }
    };
  };

  render() {
    const { id, name, done } = this.props;
    const { mouse } = this.state;
    return (
      <div>
        <li
          style={{ background: mouse ? "#ddd" : "white" }}
          onMouseEnter={this.handleMouse(true)}
          onMouseLeave={this.handleMouse(false)}
        >
          <label>
            <input
              type="checkbox"
              checked={done}
              onChange={this.handleCheck(id, done)}
            />
            <span>{name}</span>
          </label>
          <button
            onClick={this.handleDelete(id, name)}
            className="btn btn-danger"
            style={{ display: mouse ? "block" : "none" }}
          >
            删除
          </button>
        </li>
      </div>
    );
  }
}

List.jsx

import React, { Component } from "react";
import Item from "../Item";
import PropTypes from "prop-types";
import "./index.css";
export default class index extends Component {
  static propTypes = {
    updateTodo: PropTypes.func.isRequired,
    deleteTodo: PropTypes.func.isRequired,
    todos: PropTypes.array.isRequired,
  };
  render() {
    const { todos, updateTodo,deleteTodo } = this.props;

    return (
      <ul className="todo-main">
        {todos.map((n) => {
          return <Item key={n.id} {...n} updateTodo={updateTodo} deleteTodo={deleteTodo}></Item>;
        })}
      </ul>
    );
  }
}

效果演示

 注意:此处CSS样式没有上传

Gitee链接:React_Study_Ac: React-Study

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

⁡⁢⁡⁢⁠Ac

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

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

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

打赏作者

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

抵扣说明:

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

余额充值