IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React类式组件TodoList案例 -> 正文阅读

[JavaScript知识库]React类式组件TodoList案例

尚硅谷2021版React技术全家桶全套完整版(零基础入门到精通/男神天禹老师亲授)

在看了老师的讲解后,自己打了一遍,以下总结了一下老师说的注意点和自己编写代码时注意点,后面附上自己写的代码。
在这里插入图片描述

流程

1. 创建项目并启动

  • 全局安装 npm i/yarn -g create-react-app

  • 创建项目 create-react-app 项目名称

  • 启动项目 npm start/yarn start

2. 拆分组件、实现静态组件

原生HTML转化为ReacDom时注意以下问题:

  • 替换 class= 为 className=
  • 替换style = “…” 为 {{…}} 且注意内部引号问题
  • 标签闭和" / ",尤其是input、br

3.实现动态组件

  • 组件存放位置
    【单个】组件使用:放在其自身的state中
    【多个】组件使用:放在共同的父组件state中(状态提升)

  • 状态在哪里,操作状态的方法就在哪里

  • 父子通信:
    【父】→【子】:通过props传递
    【子】→【父】:通过props传递,在子组件中定义函数并将数据作为参数传递出去

  • 自动生成唯一标识符id:nanoid,详情请看https://github.com/ai/nanoid

  • 注意defaultChecked 和 checked的区别,类似的还有:defaultValue 和 value

App.jsx

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 = {
    todos: [
      { id: '001', name: '吃饭', done: true },
      { id: '002', name: '睡觉', done: true },
      { id: '003', name: '打代码', done: false },
      { id: '004', name: '逛街', done: false }
    ]
  }
  addTodoObj = (newObj) => {
    const { todos } = this.state
  
    const newTodos = [newObj, ...todos]
    this.setState({ todos: newTodos })
  }
 
  updateTodos = (id) => {
    console.log(id)
    this.setState({
      todos: this.state.todos.map(item => {
        return item.id === id ? { ...item, done: !item.done } : item
      })
    })
  }
  deleteTodos = (id) => {
    this.setState({
      todos: this.state.todos.filter(item => item.id !== id)
    })
  }
  deleteAllDoneTodo = () => {
    this.setState({
      todos: this.state.todos.filter(item => !item.done)
    })
  }
  toggleAllSelect = (state) => {
    this.setState({
      todos: this.state.todos.map(item => {
        return { ...item, done: state }
      })
    })
  }
  render() {
    const { todos } = this.state
    const length = todos.length
    const doneLength = todos.reduce((total, item) => item.done ? total + 1 : total, 0)
    return (
      <div className="todo-container">
        <div className="todo-wrap">
          <Header addTodoObj={this.addTodoObj} />
          <List todos={todos} updateTodos={this.updateTodos} deleteTodos={this.deleteTodos} />
          <Footer length={length} doneLength={doneLength} deleteAllDoneTodo={this.deleteAllDoneTodo} toggleAllSelect={this.toggleAllSelect} />
        </div>
      </div>
    )
  }
}

  1. ES6 数组和对象的合并
    在这里插入图片描述
  2. 事件定义时会受到参数,但绑定时无(),故不用 函数柯里化!!!(这是我当时犯的一个低级错误)。

Header

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { nanoid } from 'nanoid'
import './index.css'

export default class Header extends Component {
	static propTypes = {
		addTodoObj: PropTypes.func.isRequired,
	}
	handleKeyUp = (event) => {
		const x = event.which || event.keyCode;
		if (x !== 13) return
		if (event.target.value.trim() === '') {
			alert('输入不能为空')
			return
		}
		const newObj = { 
			id: nanoid(), 
			name: event.target.value, 
			done: false 
		}
		this.props.addTodoObj(newObj)
		event.target.value = ''
	}
	render() {
		return (
			<div className="todo-header">
				<input type="text" placeholder="请输入你的任务名称,按回车键确认" onKeyUp={this.handleKeyUp} />
			</div>
		)
	}
}
  1. keyCode兼容性
    在 Firefox 中, keyCode 属性在 onkeypress 事件中是无效的 (返回 0)。
    浏览器兼容问题,可以一起使用 which 和 keyCode 属性来解决:

  2. 易忘点:判断输入值不能为空

List

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Item from '../Item'
import './index.css'
export default class List extends Component {
	static propTypes = {
		todos: PropTypes.array.isRequired,
		updateTodos: PropTypes.func.isRequired,
		deleteTodos: PropTypes.func.isRequired
	}
	render() {
		const { todos, updateTodos, deleteTodos } = this.props
		return (
			<ul className="todo-main">
				{
					todos.map(item => {
						return <Item {...item} key={item.id} updateTodos={updateTodos} deleteTodos={deleteTodos} />
					})
				}
			</ul>
		)
	}
}
  1. 不要忘了绑定key值
  2. 事件绑定时时render内部变量,不要同this

Item

import React, { Component } from 'react'
import './index.css'
export default class Item extends Component {
	state = { mouseState: false }
	handlerMouseEvent = (flag) => {
		return () => {
			this.setState({ mouseState: flag })
		}
	}

	updateTodos = (id) => {
		return () => {
			this.props.updateTodos(id)
		}
	}

	deleteTodo = (id) => {
		return () => {
			if (window.confirm('确定删除吗?')) {
				this.props.deleteTodos(id)
			}
		}
	}

	render() {
		const { id, name, done } = this.props
		const { mouseState } = this.state
		return (
			<li style={{ background: mouseState ? '#ddd' : '#fff' }} onMouseEnter={this.handlerMouseEvent(true)} onMouseLeave={this.handlerMouseEvent(false)} >
				<label>
					<input type="checkbox" checked={done} onChange={this.updateTodos(id)} />
					<span>{name}</span>
				</label>
				<button className="btn btn-danger" onClick={this.deleteTodo(id)} style={{ display: mouseState ? 'block' : "none" }}>删除</button>
			</li>
		)
	}
}

  1. 易忘点:删除时的弹框确认
  2. 函数柯里化
  3. 鼠标的移入移出,通过一个状态值来确认

Footer

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import './index.css'
export default class Footer extends Component {
  static propTypes = {
    doneLength: PropTypes.number.isRequired,
    length: PropTypes.number.isRequired,
    toggleAllSelect: PropTypes.func.isRequired,
    deleteAllDoneTodo: PropTypes.func.isRequired
  }

  render() {
    const { length, doneLength, toggleAllSelect, deleteAllDoneTodo } = this.props
    return (
      <div className="todo-footer">
        <label>
          <input type="checkbox" checked={length === doneLength && length > 0} onChange={event => toggleAllSelect(event.target.checked)} />
        </label>
        <span>
          <span>已完成{doneLength}</span> / 全部{length}
        </span>
        <button className="btn btn-danger" onClick={deleteAllDoneTodo}>清除已完成任务</button>
      </div>

    )
  }
}
  1. 最后都将defaultChecked转化为checked,否则数据改变了但界面无变化
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-22 14:35:15  更:2021-09-22 14:35:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 12:35:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计