React 入门:实战案例 TodoList 修改 Todo Item的状态

news2024/11/20 10:21:16

文章目录

  • 目标实现效果
  • 实现思路
  • 实现步骤
    • 第一步:定义更改 Todo 状态的方法,以供调用
    • 第二步:App 组件传递更改 Todo 状态的方法给子组件 List
    • 第三步:List 组件传递更改 Todo 状态的方法给子组件 Item
    • 第四步:Item 调用更改 Todo 状态的方法,更新状态
  • 完整代码
    • App 组件完整代码
    • List 组件完整代码
    • Item 组件完整代码

本文实现点击 Item 组件的复选框 checkbox 时,切换复选框的选中状态,同时更新 TodoList 在组件状态 State 中的数据状态。以此来模拟实现 TodoList 的真实业务逻辑,即选中表示完成某条代办事项,取消表示未完成。

当然真实项目中,除了更改组件状态 State,同时还需要通过请求服务端的 API 接口,将数据保存到数据库中。

目标实现效果

在这里插入图片描述

实现思路

通过上文的介绍,要涉及到组件之间的通信,由于存在用户操作触发组件状态数据的更新,所以实现思路上和添加一条 Todo 类似。但是添加 Todo 只是 App 组件和 Header 组件两级之间的通信逻辑,而 Item 组件和 App 组件没有直接的关系,无法直接通信,所以需要通过 List 组件来作为通信的桥梁。虽然是三级,但实现本质都是一样的。

实现步骤

第一步:定义更改 Todo 状态的方法,以供调用

先引入一个概念:

状态在哪里,操作(更改)状态的方法就在哪里。

通过 TodoList 来解释上面的概念,通俗的讲,我们要修改组件状态中的 TodoList 的数据,而 TodoList 定义在 App 组件的状态中,那么我们就要在 App 组件中定义更改 Todo 的方法。可以回头想想,添加 Todo 代码是不是这样的呢?

代码片段如下:

// file: src/App.js

/**
 * App 组件
 */
export default class App extends Component {
  // 初始化状态
  state = {
    todoList: [
      { id: 1, name: "参加晨会", done: true },
      { id: 2, name: "A功能开发", done: true },
      { id: 3, name: "B功能开发", done: false },
    ],
  };

  /**
   * addTodo 用于添加一条 Todo 记录,接收的参数是 Todo 对象
   */
  addTodo = (todoObj) => {
    // TODO .....
  };

  // 用于更新一个 Todo 对象
  updateTodo = (id, done) => {
    // 获取状态的中 todoList
    const { todoList } = this.state;
    // 匹配处理数据
    const newTodoList = todoList.map((todoObj) => {
      if (todoObj.id === id) return { ...todoObj, done };
      else return todoObj;
    });
    // 更新状态
    this.setState({ todoList: newTodoList });
  };

  render() {
    // TODO .....
  }
}

第二步:App 组件传递更改 Todo 状态的方法给子组件 List

App 组件通过 props 将更改 TodoList 状态的方法传给子组件 List。

代码片段如下:

// file: src/App.js

// 给 List 组件添加一个 props 属性,值为更改 Todo 状态回调方法
<List todoList={todoList} updateTodo={this.updateTodo} />

第三步:List 组件传递更改 Todo 状态的方法给子组件 Item

List 组件通过 props 接收到更改 TodoList 状态的方法,并将该方法传给子组件 Item。

代码片段如下:

// file: src/components/List/index.jsx

// 在 List 组件的 render() 方法中,从 接收获取到更新状态的方法
const { todoList, updateTodo } = this.props;

// 给 Item 组件添加一个 props 属性,值为从 props 接收到的更改 Todo 状态方法
<Item key={todo.id} {...todo} updateTodo={updateTodo} />;

第四步:Item 调用更改 Todo 状态的方法,更新状态

Item 组件通过 props 接收到更改 TodoList 状态的方法,当鼠标点击 Item 组件时,通过 onChange 事件进行监听,在监听回调中获取当前复选框的选中状态,也就是当前操作的 Item 组件实例的状态,然后调用从 props 接收到的更改 Todo 状态的方法,类似冒泡的形式,最终由 App 组件中的对应方法执行从而更改 TodoList 的状态。

代码片段如下:

// file: src/components/Item/index.jsx

// 定义勾选、取消勾选某一个 Todo 的回调方法
handleCheck = (id) => {
  // 此处一定要使用高阶函数,为什么?请阅读本专栏《受控组件和非受控组件》章节相关内容内容
  return (event) => {
    /**
     * 注意两点:
     * 1. 需要通过 event.target 的 checked 属性来获取复选框是否选中的状态值,而不是 value;
     * 2. 直接通过 this.props 调用方法
     */
    this.props.updateTodo(id, event.target.checked);
  };
};

// 给 checkbox 绑定 onChange 事件
<input type="checkbox" defaultChecked={done} onChange={this.handleCheck(id)} />;

至此我们就完成了更改 Item 的状态。

完整代码

App 组件完整代码

// file: src/App.js

import React, { Component } from "react";
import Header from "./components/Header";
import List from "./components/List";
import Footer from "./components/Footer";
import "./App.css";

export default class App extends Component {
  // 总结:状态在哪里,操作状态的方法就在哪里。

  // 初始化状态
  state = {
    todoList: [
      { id: 1, name: "参加晨会", done: true },
      { id: 2, name: "A功能开发", done: true },
      { id: 3, name: "B功能开发", done: false },
    ],
  };

  /**
   * addTodo 用于添加一条 Todo 记录,接收的参数是 Todo 对象
   */
  addTodo = (todoObj) => {
    // 获取原 TodoList
    const { todoList } = this.state;
    // 追加一条 Todo
    const newTodoList = [todoObj, ...todoList];
    // 更新状态
    this.setState({ todoList: newTodoList });
  };

  // 用于更新一个 Todo 对象
  updateTodo = (id, done) => {
    // 获取状态的中 todoList
    const { todoList } = this.state;
    // 匹配处理数据
    const newTodoList = todoList.map((todoObj) => {
      if (todoObj.id === id) return { ...todoObj, done };
      else return todoObj;
    });
    // 更新状态
    this.setState({ todoList: newTodoList });
  };

  render() {
    const { todoList } = this.state;
    return (
      <div className="todo-container">
        <div className="todo-wrap">
          <Header addTodo={this.addTodo} />
          <List todoList={todoList} updateTodo={this.updateTodo} />
          <Footer />
        </div>
      </div>
    );
  }
}

List 组件完整代码

// file: src/components/List/index.jsx

import React, { Component } from "react";
import Item from "../Item";
import "./index.css";

export default class List extends Component {
  render() {
    const { todoList, updateTodo } = this.props;
    return (
      <ul className="todo-main">
        {todoList.map((todo) => {
          return <Item key={todo.id} {...todo} updateTodo={updateTodo} />;
        })}
      </ul>
    );
  }
}

Item 组件完整代码

// file: src/components/Item/index.jsx

import React, { Component } from "react";
import "./index.css";

export default class Item extends Component {
  state = { mouse: false }; //标识鼠标移入、移出

  // 鼠标移入、移出的回调
  handleMouse = (flag) => {
    return () => {
      this.setState({ mouse: flag });
    };
  };

  // 勾选、取消勾选某一个 Todo 的回调
  handleCheck = (id) => {
    return (event) => {
      this.props.updateTodo(id, event.target.checked);
    };
  };

  render() {
    const { id, name, done } = this.props;
    const { mouse } = this.state;
    return (
      <li
        style={{ backgroundColor: mouse ? "#eee" : "#fff" }}
        onMouseEnter={this.handleMouse(true)}
        onMouseLeave={this.handleMouse(false)}
      >
        <label className="container">
          <input
            type="checkbox"
            defaultChecked={done}
            onChange={this.handleCheck(id)}
          />
          <span>{name}</span>
        </label>
        <button
          className="btn btn-danger btn-sm"
          style={{ display: mouse ? "block" : "none" }}
        >
          删除
        </button>
      </li>
    );
  }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/76977.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring 6.0 正式发布,一文了解新特性

正式发布 Spring Framework 6.0 首个 RC 版本正式发布&#xff0c;可以开始使用了。 新特性 我们一起来看看这次6.0版本带来了哪些特性&#xff1f;需要注意的是该版本整个框架代码库现在基于 Java 17 源代码级别&#xff0c;所以如果你想使用需要升级版本到 JDK 17 才可以&a…

什么是FPGA fpga的核心作用

fpga名词解释&#xff1a;FPGA是英文Field Programmable Gate Array的缩写&#xff0c;即现场可编程门阵列&#xff0c;它是在PAL、GAL、EPLD等可编程器件的基础上进一步发展的产物。 fpga核心做用&#xff1a;它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的&#…

【吴恩达机器学习笔记】十七、总结

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

计算机毕业设计springboot+vue基本医院公众号建设推动医疗卫生服务现状研究

项目介绍 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,医院公众号建设推动医疗卫生服务就是信息时代变革中的产物之一。 任…

从零开始学Java之eclipse的安装配置与使用,看这篇就够了

前言 在上一篇文章中&#xff0c;壹哥给大家介绍了Notepad这个更高级点的记事本&#xff0c;它进行Java开发相比windows自带的记事本要更方便一些。但是即便如此&#xff0c;用这种记事本进行Java开发效率依然很低。如果是少量的代码编写还好说&#xff0c;大量代码的开发&…

计算机毕业设计springboot+vue基本微信小程序的电子书阅读器小程序

项目介绍 随着信息技术和网络技术的飞速发展,人类已进入全新信息化时代,传统管理技术已无法高效,便捷地管理信息。为了迎合时代需求,优化管理效率,各种各样的管理系统应运而生,各行各业相继进入信息管理时代,电子书阅读器小程序就是信息时代变革中的产物之一。 任何系统都要遵循…

【云原生】Kubernetes(k8s)Istio Gateway 介绍与实战操作

文章目录一、概述二、Istio 架构三、通过 istioctl 部署 Istio1&#xff09;安装istioctl 工具2&#xff09;通过istioctl安装istio3&#xff09;检查四、Istio Gateway五、Istio VirtualService 虚拟服务六、示例演示&#xff08;bookinfo&#xff09;1&#xff09;安装bookin…

MATLAB | 一起来感受数学之美,第一届迷你黑客大赛回顾

Hey真的是好久不见&#xff0c;最近确实是比较忙更新频率也下来了&#xff0c;过段时间应该能恢复正常更新速度&#xff0c;之前给大家解说过今年举办的math is beautiful迷你黑客大赛&#xff0c;但这其实是第二届大赛&#xff0c;本期推送带大家回顾一下第一期大赛&#xff0…

为什么索引可以让查询变快?终于有人说清楚了!

概述 人类存储信息的发展历程大致经历如下&#xff1a; 由于是个人凭着自己理解总结的&#xff0c;因此可能不一定精确&#xff0c;但是毋庸置疑的是&#xff0c;在当代&#xff0c;各大公司机构部门的数据都是维护在数据库当中的。 数据库作为数据存储介质发展的最新产物&am…

大数据面试之MapReduce常见题目

大数据面试之MapReduce常见题目 MapReduce中Shuffle过程及优化 1.1 Shuffle的详细图解 1.2 Shuffle的详细文字过程 Shuffle文字部分描述&#xff1a; ​ Shuffle横跨Map和Reduce阶段&#xff0c;是指map()方法之后&#xff0c;reduce()方法之前&#xff0c;中间这段汇洗的过…

Web前端大作业制作个人网页(html+css+javascript)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

功能强大UI美观的视频答题猜歌闯关娱乐微信小程序源码下载

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 这是一款拥有后端的闯关娱乐小程序 支持个人小程序和企业小程序上线运营 功能强大齐全,带数据本地化 (数据在自己服务器自己管理无需担心第三方失效的问题) 支持看视频答题闯关 支持…

Java多线程处理笔记

学习视频:598-JavaSE进阶-多线程概述_哔哩哔哩_bilibili 目录 多线程概述 进程和线程的关系 多线程并发的理解 分析程序存在几个线程 实现线程的第一种方式 实现线程的第二种方式 采用匿名内部类的方式 线程生命周期 获取线程的名字 获取当前线程对象 线程的sleep方法 …

Spring Cloud Stream 结合rocketmq

Spring Cloud Stream 结合rocketmq 官方网址&#xff1a;https://github.com/alibaba/spring-cloud-alibaba/wiki/RocketMQ 你可以在这个地址上下载到相关示例项目&#xff0c;配置项等相关信息 spring-cloud-stream 文档&#xff08;这个地址似乎只有集合kafaka和rabbit的示…

Akka 学习(六)Actor的监督机制

目录一 监督机制1.1 错误隔离性1.2 系统冗余性1.3 Actor的监督1.3.1 监督体系1.3.2 理解1,3.3 监督策越一 监督机制 1.1 错误隔离性 在学习Akka如何对失败情况进行响应之前&#xff0c;先了解一些在分布式应用程序中都应该遵循的通用策略&#xff1a;隔离错误。假设每个组件都…

【刷题-数组篇】狂刷力扣三十题,“数组”嘎嘎乱写 | 2022 12-5到12-9

前言 &#xff08;12月5日&#xff09;突然想起了很久以前别人&#xff08;具体来源已经记不清了&#xff09;传给我的一套题单。网上的题单不少&#xff0c;光收藏可不行&#xff0c;关键还得下手。 这套题单的题目数量为300出头&#xff0c;什么时候刷完我还没有明确计划&a…

web前端大作业 (仿英雄联盟网站制作HTML+CSS+JavaScript) 学生dreamweaver网页设计作业

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

2.IOC之xml配置

1.使用IDEA创建工程 2.引入项目使用的依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency> </depe…

英文外链代发怎么做有效果?英文外链购买平台

英文外链代发怎么做有效果&#xff1f; 答案是&#xff1a;选择权重较好的GPB外链 我们首先要知道一个观点&#xff0c;什么样的外链才有效果&#xff1f; 1.英文外链网站的有一定的权重&#xff0c;可高可低&#xff0c;但一定要有权重&#xff0c;数值指标可以参考MOZ的Do…

10.AOP之xml配置

1.使用IDEA创建工程 2.引入项目使用的依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.2.RELEASE</version></dependency><depend…