二、【React脚手架】组件化编码(TodoList案例)

news2025/4/16 18:21:18

文章目录

  • 1、组件化编码流程(通用)
  • 2、样式覆盖问题
  • 3、DEMO
    • 3.1、需要实现的效果
    • 3.2、前期须知
    • 3.3、项目结构
    • 3.4、CODE
      • 3.4.1、App.js
      • 3.4.2、App.css
      • 3.4.3、Header
      • 3.4.4、List
      • 3.4.5、Item
      • 3.4.6、Footer

1、组件化编码流程(通用)

  1. 拆分组件: 拆分界面,抽取组件

  2. 实现静态组件: 使用组件实现静态页面效果

  3. 实现动态组件

    1. 动态显示初始化数据
      1. 数据类型
      2. 数据名称
      3. 保存在哪个组件?
    2. 交互(从绑定事件监听开始)

2、样式覆盖问题

  1. 使用 less,例如import '.\xxx.less',样式采用嵌套格式,顶级样式名不重即可,建议使用组件名
    1. 也可使用2的方法,此时不必写 .module
  2. css样式文件加 .module,例如 xxx.module.css
    1. 用参数命名引入这个样式文件: import styles from 'xxx.module.css'
    2. 使用时采用react插值方式:className={styles.xx}

3、DEMO

3.1、需要实现的效果

在这里插入图片描述

3.2、前期须知

  • 如果要对 props 进行限制,需要引入 prop-types 库

    • 安装指令:yarn add prop-types

    • 引入指令:import PropTypes from 'prop-types'

    • 使用限制:static propTypes = { addOne: PropTypes.func.isRequired }

    • 使用可参考 五、【React基础】组件实例三大核心属性之二 props 中 2、3 栏

  • id 需要使用不重复随机数,推荐使用nanoid

    • 安装指令:yarn add nanoid

    • 引入函数:import { nanoid } from 'nanoid'

    • 使用函数:nanoid()

3.3、项目结构

只有红框内的文件有修改或是新增的

在这里插入图片描述

3.4、CODE

3.4.1、App.js

import React, { Component } from 'react'
import { nanoid } from 'nanoid'
import Header from './components/ToDoList/Header'
import List from './components/ToDoList/List'
import Footer from './components/ToDoList/Footer'
import './App.css'

export default class App extends Component {

  state = {
    todoList: [{
      id: '001',
      name: '吃饭',
      done: false
    }, {
      id: '002',
      name: '睡觉',
      done: false
    }, {
      id: '003',
      name: '打豆豆',
      done: false
    }]
  }

  toNever = id => {
    const { todoList } = this.state
    todoList.map(item => {
      if (item.id === id) {
        item.done = !item.done
      }
      return item
    })
    this.setState({ todoList })
  }

  addOne = name => {
    const { todoList } = this.state
    this.setState({
      todoList: [
        {
          id: nanoid(),
          name,
          done: false
        },
        ...todoList
      ]
    })
  }

  deleteById = id => {
    if (!window.confirm('确定删除吗?')) return
    const { todoList } = this.state
    this.setState({ todoList: todoList.filter(item => item.id !== id) })
  }

  deleteDone = () => {
    if (!window.confirm('确定删除吗?')) return
    const { todoList } = this.state
    this.setState({ todoList: todoList.filter(item => !item.done) })
  }

  doneAllOrNot = () => {
    const { todoList } = this.state
    const dones = todoList.filter(i => i.done).length

    todoList.map(item => {
      item.done = !(todoList.length === dones)
      return item
    })
    this.setState({ todoList })
  }

  render() {
    return (
      <div className="todo-container" >
        <div className="todo-wrap">
          <Header addOne={this.addOne} />
          <List {...this.state} toNever={this.toNever} deleteById={this.deleteById} />
          <Footer {...this.state} doneAllOrNot={this.doneAllOrNot} deleteDone={this.deleteDone} />
        </div>
      </div>
    );
  }
}

3.4.2、App.css

/*base*/
body {
    background: #fff;
}

.btn {
    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;
    display: none;
    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;
}

.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-left: 0px;
    border: 1px solid #ddd;
    border-radius: 2px;
    padding: 0px;
}

.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;
    display: flex;
    justify-content: space-between;
}

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: 3px;
}

li:hover .btn {
    display: 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;
}

.todo-footer:hover .btn {
    display: block;
}

3.4.3、Header

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

export default class Header extends Component {

    static propTypes = {
        addOne: PropTypes.func.isRequired
    }

    add = e => {
        const { addOne } = this.props
        if (e.key === 'Enter') {
            if (!!e.target.value.trim()) {
                addOne(e.target.value)
                e.target.value = ''
            } else {
                alert('请输入非空任务名')
            }
        }
    }
    render() {
        return (
            <div className="todo-header">
                <input type="text" placeholder="请输入你的任务名称,按回车键确认" onKeyUp={this.add} />
            </div>
        )
    }
}

3.4.4、List

import React, { Component } from 'react'
import Item from './Item'

export default class List extends Component {

    render() {
        const { todoList, toNever, deleteById } = this.props
        return (
            <ul className="todo-main">
                {
                    todoList.map(item => <Item key={item.id} todo={item} toNever={toNever} deleteById={deleteById} />)
                }
            </ul>
        )
    }
}

3.4.5、Item

import React, { Component } from 'react'

export default class Item extends Component {
    render() {
        const { id, name, done } = this.props.todo
        const { toNever, deleteById } = this.props
        return (
            <li>
                <label>
                    <input type="checkbox" checked={done} onChange={() => toNever(id)} />
                    <span>{name}</span>
                </label>
                <button className="btn btn-danger" onClick={() => deleteById(id)}>删除</button>
            </li>
        )
    }
}

3.4.6、Footer

import React, { Component } from 'react'

export default class Footer extends Component {
    render() {
        const { todoList, doneAllOrNot, deleteDone } = this.props
        const total = todoList.length
        const done = todoList.filter(item => item.done).length
        return (
            <div className="todo-footer">
                <label>
                    <input type="checkbox" checked={!!(total || 0) && total === done} onChange={doneAllOrNot} />
                </label>
                <span>
                    <span>已完成{done || 0}</span> / 全部{total || 0}
                </span>
                <button className="btn btn-danger" onClick={deleteDone}>清除已完成任务</button>
            </div>
        )
    }
}


小白学习参考视频:尚硅谷React教程

中文官网:React 官方中文文档

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

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

相关文章

Python 面向对象简介

什么是面向对象&#xff1f; 面向对象是一种编程思想&#xff0c;在开发过程中关注的不是解决问题的步骤和过程&#xff0c;而是参与解决问题的对象和它们具备的行为。 01 面向过程和面向对象的区别 1、面向过程 面向过程在开发过程中关注的是解决问题的步骤和过程&#xf…

《计算机体系结构量化研究方法第六版》1.6 成本趋势

1.6.1 时间、产量和大众化的影响 即便没有技术进步&#xff0c;计算机组件的制造成本也会随着时间的推移而降低。这背后有着学习曲线的因素。 【学习曲线&#xff08;from百度&#xff09;】 学习曲线的定义为"在一定时间内获得的技能或知识的速率"&#xff0c;又称…

2022王道OS 1.4 操作系统的体系结构 chap1回顾

2022王道OS 1.4 操作系统的体系结构 & chap1回顾 操作系统的体系结构 知识总览 操作系统的内核 时钟管理&#xff1a;利用时钟中断实现计时功能 原语&#xff1a;一种特殊的程序&#xff0c;具有原子性&#xff08;一气呵成&#xff0c;不可被中断&#xff09; 内核是操…

人工智能开启甲骨文整理研究新范式

编者按&#xff1a;在甲骨学研究中&#xff0c;甲骨“校重”整理是一项费事费力但又极其重要的基础性研究工作。微软亚洲研究院与首都师范大学甲骨文研究中心莫伯峰教授团队合作开发的甲骨文校重助手Diviner&#xff0c;第一次将自监督AI模型引入到甲骨文“校重”工作中&#x…

【Mysql】数据库的基本操作和表的基本操作

本章内容是,用sql语言实现对数据库的基本操作和表的基本操作 文章目录前言1. 数据库的基本操作1.1 创建数据库1.2 查看数据库1.3 选中数据库1.4 删除数据库2. 数据库基本数据类型3. 表的基本操作3.1 创建表3.2 显示数据库中的表3.3 查看表的构造3.4 删表4. 表的增删改查4.1 增加…

使用synchronized 加锁你加对了么?

本文讲解使用synchronized只是对synchronized的使用,底层原理将在后续文章 目录 从实际中理解共享带来的问题 Java代码实现共享带来的问题进行分析 临界区(Critical Section) 与 竞态条件(Race Condition) 临界区 竞态条件 synchronized解决方案 怎么理解synchronized中…

【web前端期末大作业】基于HTML+CSS+JavaScript实现代理商销售管理系统后台(8页)

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

mathtype在word内的简单使用

一、简单使用 1、快捷键 快捷键说明ctrlaltQ行内公式altshiftQ右编号&#xff08;行间公式&#xff09;\ ;{空格、大括号都需要转义ALTF4关闭mathtype窗口 2、小技巧 \left与\right 一定要配对使用&#xff0c;且对于对称的符号&#xff08;如(), {}等&#xff09;来说&…

【Linux】---进程控制(创建、终止、等待、替换)

文章目录进程创建fork()进程退出进程退出场景进程退出方法退出码exit、_exit进程等待进程等待的方法waitwaitpid阻塞和非阻塞进程替换替换的原理替换所用到的函数execlexeclpexecle简易的shell进程创建 fork() fork函数在之前的文章中也已经提到过了。其主要作用是从已存在的…

excel提示stdole32.tlb的解决方法

大家在使用excel时有遇到stdole32.tlb错误提示吗&#xff1f;出现这个问题直接导致excel无法启动&#xff0c;非常影响用户的工作效率。为了顺利解决问题&#xff0c;小编给大家带来了详细的解决办法&#xff0c;希望可以帮到你。 win7系统打开excel提示stdole32.tlb的解决方法…

Nosql inject注入

0x00 Nosql inject 最近主要在看那个 YApi 的注入漏洞&#xff0c;也是一个 mongodb的注入 所以来写一下这个东西&#xff0c;其实现在越来越常见的Nosql注入 感觉很多分布式和一些新的系统已经大量使用这种nosql数据库&#xff0c;这个注入和传统的关系型数据库有一点点不同…

【Hack The Box】linux练习-- Meta

HTB 学习笔记 【Hack The Box】linux练习-- Meta &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月27日&#x1f334; &#x1f36d…

[附源码]计算机毕业设计springboot“科教兴国”支教门户网站

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

复旦MBA项目GNW海外课程|连线全球顶尖商学院,跨时空学习精彩无限!

10月下旬&#xff0c;复旦MBA为期一周的GNW海外课程落下帷幕&#xff0c;复旦在职MBA的同学们通过云端连线&#xff0c;走进全球多所顶级商学院&#xff0c;与深谙商道、学术造诣深厚的教授学者&#xff0c;以及来自不同地域不同文化背景的精英学生取经论道。      复旦MBA…

深入理解死锁问题

死锁问题&#x1f3de;️1. 死锁概念&#x1f301;2. 为什么发生死锁&#x1f320;3. 产生死锁的条件&#x1f301;4. 如何避免死锁&#x1f4d6;4.1 循环等待&#x1f4d6;4.2 持有并等待&#x1f4d6;4.3 非抢占&#x1f4d6;4.4 互斥&#x1f33f;5. 通过调度避免死锁&#…

【Python开发】一文详解Flask-Login

一文详解Flask-LoginFlask-Login 为 Flask 提供用户会话管理。它处理登录、注销和长时间记住用户会话等常见任务。 Flask-Login 不绑定到任何特定的数据库系统或权限模型。唯一的要求是您的 用户对象实现一些方法&#xff0c;并且您向能够 从用户 ID 加载用户 的扩展提供回调。…

Kotlin 开发Android app(十二):Android布局FrameLayout和ViewPager2控件实现滚动广告栏

在上一节中我们简单的介绍了RecyclerView 的使用&#xff0c;他是整个开发的重点控件&#xff0c;这一节我们来看看FrameLayout 布局结合ViewPager2&#xff0c;开发一个广告控件。 新模块banner 先创建一个新的模块&#xff0c;取名为banner&#xff0c;用来创建我们的滚动广…

Spring Boot自定义Namespace

Spring Boot 自定义Namespace 在学些Spring Boot 自定义Namespace之前&#xff0c;先来看一个简单的案例。在Spring Boot出现之前&#xff0c;所有的bean都是在XML文件的格式 中定义。为了管理方便&#xff0c;一些大型复杂的应用系统&#xff0c;通常定个多个xml文件来共同满…

【笑小枫的按步照搬系列】JDK8下载安装配置

笑小枫&#x1f495; 欢迎来到笑小枫的世界&#xff0c;喜欢的朋友关注一下我呦&#xff0c;大伙的支持&#xff0c;就是我坚持写下去的动力。 微信公众号&#xff1a;笑小枫 笑小枫个人博客&#xff1a;https://www.xiaoxiaofeng.com 一、安装 1、方式一&#xff1a;进入官网…

Apifox:成熟的测试工具要学会自己写接口文档

好家伙&#xff0c; 在开发过程中&#xff0c;我们总是避免不了进行接口的测试&#xff0c; 而相比手动敲测试代码&#xff0c;使用测试工具进行测试更为便捷&#xff0c;高效 今天发现了一个非常好用的接口测试工具Apifox 相比于Postman&#xff0c;他还拥有一个非常nb的功…