在学习了 react 的父子组件通讯后,尝试着做了一个大致如下的 todomvc 案例:

这里关于 todomvc 的基本结构及样式就不去过多的描述了

我们可以去 github todumvc 样板

上进行下载其基本的结构

大致结构如下:

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/import React from 'react';import ReactDom from 'react-dom/client';import { Component } from 'react';import './styles/base.css';import './styles/index.css'class App extends Component {render() {return (<section className="todoapp"><header className="header"><h1>todos</h1><input className="new-todo" placeholder="What needs to be done?" autoFocus /></header><section className="main"><input id="toggle-all" className="toggle-all" type="checkbox" /><label htmlFor="toggle-all">Mark all as complete</label><ul className="todo-list"><li className="completed"><div className="view"><input className="toggle" type="checkbox" checked /><label>Taste JavaScript</label><button className="destroy"></button></div><input className="edit" value="Create a TodoMVC template" /></li><li><div className="view"><input className="toggle" type="checkbox" /><label>Buy a unicorn</label><button className="destroy"></button></div><input className="edit" value="Rule the web" /></li></ul></section><footer className="footer"><span className="todo-count"><strong>0</strong> item left</span><ul className="filters"><li><a className="selected" href="#/">All</a></li><li><a href="#/active">Active</a></li><li><a href="#/completed">Completed</a></li></ul><button className="clear-completed">Clear completed</button></footer></section>)}}// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (<React.Fragment><App></App></React.Fragment>
);// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

接着我们需要做的就是将其进行组件化拆分,大致分为如下三个部分:

在 src 目录下新建 components 文件夹,专门用来存放组件

将 src/index.js 文件进行如上图拆分

components/TodoHeader.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {return (<header className="header"><h1>todos</h1><input className="new-todo" placeholder="What needs to be done?" autoFocus /></header>)}
}

components/TodoMain.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {return (<section className="main"><input id="toggle-all" className="toggle-all" type="checkbox" /><label htmlFor="toggle-all">Mark all as complete</label><ul className="todo-list"><li className="completed"><div className="view"><input className="toggle" type="checkbox" checked /><label>Taste JavaScript</label><button className="destroy"></button></div><input className="edit" value="Create a TodoMVC template" /></li><li><div className="view"><input className="toggle" type="checkbox" /><label>Buy a unicorn</label><button className="destroy"></button></div><input className="edit" value="Rule the web" /></li></ul></section>)}
}

components/TodoFooter.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {return (<footer className="footer"><span className="todo-count"><strong>0</strong> item left</span><ul className="filters"><li><a className="selected" href="#/">All</a></li><li><a href="#/active">Active</a></li><li><a href="#/completed">Completed</a></li></ul><button className="clear-completed">Clear completed</button></footer>)}
}

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/import React from 'react';import ReactDom from 'react-dom/client';import { Component } from 'react';import './styles/base.css';import './styles/index.css'import TodoHeader from './components/TodoHeader';import TodoMain from './components/TodoMain';import TodoFooter from './components/TodoFooter';class App extends Component {render() {return (<section className="todoapp"><TodoHeader></TodoHeader><TodoMain></TodoMain><TodoFooter></TodoFooter></section>)}}// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (<React.Fragment><App></App></React.Fragment>
);// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

在完成了上面的步骤之后,从这里开始,正式进行案例的开发

首先,我们需要实现的就是 任务列表渲染功能

这里需要先在父组件(index.js)里准备数据,然后传递到子组件(TodoMain.js)里进行展示,就需要用到组件通讯里的父传子:

  1. 父组件提供要传递的state数据

  2. 给子组件标签添加属性,值为 state 中的数据

  3. 子组件中通过 props 接收父组件中传递的数据

注意:接收数据:函数组件通过参数props接收数据,类组件通过this.props接收数据

TodoMain.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {const { list } = this.props;return (<section className="main"><input id="toggle-all" className="toggle-all" type="checkbox" /><label htmlFor="toggle-all">Mark all as complete</label><ul className="todo-list">{list.map(item => {return (<li className={item.done ? 'completed' : ''} key={item.id}><div className="view"><input className="toggle" type="checkbox" checked={item.done} /><label>{item.name}</label><button className="destroy"></button></div><input className="edit" value="Create a TodoMVC template" /></li>)})}</ul></section>)}
}

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/import React from 'react';import ReactDom from 'react-dom/client';import { Component } from 'react';import './styles/base.css';import './styles/index.css'import TodoHeader from './components/TodoHeader';import TodoMain from './components/TodoMain';import TodoFooter from './components/TodoFooter';class App extends Component {state = {list: [{id: 1,name: 'JavaScript',done: false},{id: 2,name: 'Vue',done: false},{id: 3,name: 'react',done: true}]}render() {const { list } = this.state;//  console.log(list);return (<section className="todoapp"><TodoHeader></TodoHeader><TodoMain list={list}></TodoMain><TodoFooter></TodoFooter></section>)}}// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (<React.Fragment><App></App></React.Fragment>
);// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

其次,我们需要实现的就是 删除任务功能

当点击删除按钮时,实现删除

这就需要给每个 li 注册点击事件,实现删除

但是需要注意的就是 li 的渲染是在 TodoMain.js 里的,而数据是在 index.js(父组件)里,因此就需要用到组件通信里的子传父通过当前点击的 id 进行删除

思路:利用回调函数,父组件提供回调,子组件调用,将要传递的数据作为回调函数的参数。

  1. 父组件提供一个回调函数(用于接收数据)

  2. 将该函数作为属性的值,传递给子组件

  3. 子组件通过 props 调用回调函数

  4. 将子组件的数据作为参数传递给回调函数

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/...class App extends Component {state = {...}render() {...<TodoMain delTodoById = {this.delTodoById}></TodoMain>...}delTodoById = (id) => {this.setState({list: this.state.list.filter(item => item.id !== id)})}}...

TodoMain.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {const { list } = this.props;return (<section className="main">...<ul className="todo-list">{list.map(item => {return (...<button className="destroy" onClick={() => {this.del(item.id)}}></button>...</li>)})}</ul></section>)}// 删除del = (id) => {// console.log(id);this.props.delTodoById(id);}
}

然后,我们需要实现的就是 任务状态修改功能

这个主要就是改变 checked  的一个状态即可

但是状态的改变是定义在index.js(父组件)的state里的--done

因此只能通过组件通讯中的子传父的形式进行传递,将当前点击的那个id,传递给父组件,在父组件里找到并修改对应id的done值

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/...class App extends Component {state = {list: [{id: 1,name: 'JavaScript',done: false},{id: 2,name: 'Vue',done: false},{id: 3,name: 'react',done: true}]}render() {const { list } = this.state;return (...<TodoMain list={list} delTodoById = {this.delTodoById} updateDone = {this.updateDone}></TodoMain>...)}// 修改任务状态updateDone = (id) => {this.setState({list: this.state.list.map(item => {if(item.id === id){return {...item,done: !item.done};}else {return item;}})})}}// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (<React.Fragment><App></App></React.Fragment>
);// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

TodoMain.js

import React,{ Component } from 'react';export default class TodoHeader extends Component {render() {const { list } = this.props;return (<section className="main">...<ul className="todo-list">{list.map(item => {return (...<input className="toggle" type="checkbox" checked={item.done} onChange={() => this.updateDone(item.id)} />...)})}</ul></section>)}// 修改任务状态updateDone = (id) => {this.props.updateDone(id);}
}

接着,我们需要实现的是 添加任务 功能

对于这个功能的实现主要利用的就是键盘的回车事件

在 TodoHeader.js 中通过 value 拿到值

但是数据的增加是在 index.js 里的,也就是最终需要把数据添加到 index.js(父组件)的 list 里,因此就需要用到组件通讯中的子传父

import React,{ Component } from 'react';export default class TodoHeader extends Component {state = {name: ''}render() {return (<header className="header"><h1>todos</h1><input className="new-todo" placeholder="What needs to be done?" autoFocusvalue={this.state.name}onChange={this.addTas}onKeyUp={this.addTo}/></header>)}// 添加任务addTas = (e) => {this.setState({name: e.target.value})}addTo = (e) => {// 按下回车键后才触发if(e.keyCode !== 13){return;}if(!this.state.name.trim()){return alert('任务不能为空!');}// 添加 todothis.props.addTo(this.state.name);// 清空 namethis.setState({name: ''})}
}

index.js

/*** 1. 导入react和react-dom* 2. 创建 react 元素* 3. 把 react 元素渲染到页面*/
...class App extends Component {state = {list: [{id: 1,name: 'JavaScript',done: false},{id: 2,name: 'Vue',done: false},{id: 3,name: 'react',done: true}]}render() {const { list } = this.state;return (...<TodoHeader addTo={this.addTo}></TodoHeader>...)}...// 添加任务addTo = (name) => {//  console.log(name);this.setState({list: [{id: Date.now(),name: name,done: false} ,...this.state.list]})}}// 幽灵节点:节点不会渲染任何的内容,跟 vue 里面的 template 标签一样
const element = (<React.Fragment><App></App></React.Fragment>
);// 参数1:渲染的 react 元素即虚拟 DOM
// 参数2:需要渲染到哪个容器中
const root = ReactDom.createRoot(document.getElementById('root'));
root.render(element);

紧接着,我们需要实现的就是 双击显示 修改框

为了准确找到当前双击的这个id ,在 TodoMain.js 里通过 state 保存了一个当前双击的那个任务的 id 的状态(currentId),将当前双击的这个 id 传进去

当双击 lable 标签之后,拿到其对应的 id,并且保存到 currentId 里

在 li 里去判断 item.id 是否等于 currentId 但是这里需要同时控制两个 类名,因此我们需要通过 npm install classnames 下载 classnames

TodoMain.js

import React,{ Component } from 'react';
import classnames from 'classnames';export default class TodoHeader extends Component {state = {// 存放当前双击的idcurrentId: ''}render() {const { list } = this.props;return (<section className="main">...{list.map(item => {return (<li className={classnames({completed: item.done,editing: item.id === this.state.currentId})} key={item.id}>...<label onDoubleClick={() => this.showEdit(item.id)}>{item.name}</label>...<input className="edit" /></li>)})}</ul></section>)}...// 双击显示修改框showEdit = (id) => {// console.log(id);this.setState({currentId: id})}
}

实现双击回显任务名称

react实现todomvc相关推荐

  1. 「首席架构师推荐」React生态系统大集合

    关于React生态系统的一系列令人敬畏的事情. React React一般资源 React社区 React在线游乐场 React教程 React通用教程 React钩子 React和TypeScrip ...

  2. 框架TodoMVC(react)

    实现: 创建四个组件,分别是头组件,尾组件,list组件,item组件,存在于这个mvc中的. 在APP.js中分别引入前三个个组件(item组件是存在于list中的,所以在list中引入item组件 ...

  3. angular react_Angular 2 vs React:将会有鲜血

    angular react Angular 2 has reached Beta and appears poised to become the hot new framework of 2016. ...

  4. [转] React Hot Loader 3 beta 升级指南

    前言 在用 react-hot-loader v1.3 的时候有些深层组件不会很完美的热更新(可能是我使用有问题).然后在 react-hot-loader 首页中看到 React Hot Loade ...

  5. More than React(一)为什么ReactJS不适合复杂交互的前端项目?

    <More than React>系列的文章会一共分为五篇和一则附录.本文是第一篇,介绍用 ReactJS开发时遇到的种种问题.后面四篇文章的每一篇将会分别详细讨论其中一个问题,以及Bin ...

  6. 谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo

    谈谈我对前端组件化中"组件"的理解,顺带写个Vue与React的demo 前言 前端已经过了单兵作战的时代了,现在一个稍微复杂一点的项目都需要几个人协同开发,一个战略级别的APP的 ...

  7. 《react 思维导图笔记》

    react 在react学习中,需要安装两个包react@16.1.1 react-dom@16.1.1 react这个包是专门用来创建react组件.组件生命周期等等 react-dom里面主要封装 ...

  8. React、Preact还是Inferno?哪个是用于快速应用程序的最佳JS框架

    全文共2215字,预计学习时长6分钟 图源:unsplash JavaScript中有许多框架,且各有千秋.在过去的几个月中,笔者一直在研究各种JavaScript框架及其差异.本文中,笔者将选择三个 ...

  9. angular和vue和react的区别

    一些历史 Angular 是基于 TypeScript 的 Javascript 框架.由 Google 进行开发和维护,它被描述为"超级厉害的 JavaScript MVW 框架" ...

最新文章

  1. linux boa服务器访问 404,Linux上boa服务器的配置和使用
  2. Python学习之猜数字小游戏
  3. 联系人排序java代码_Android仿微信联系人按字母排序_脚本之家
  4. EF修改对象里面的值。。。(对象字段多的时候)
  5. '800a0005' 图片上传出现写入文件失败的错误 -- 修改pload_5xsoft.inc
  6. Django工具:Git简介与基本操作
  7. django调用支付宝
  8. python 释放链表节点_四种常见链表的实现及时间复杂度分析(Python3版)
  9. “恭喜那些拿到 Java 月薪 2 万 Offer 的人”
  10. 【codevs3955】最长严格上升子序列(加强版)
  11. 逆向工程平台 Radare2
  12. Merry Christmas
  13. SAP BW 例程(Routine)【开始例程、关键值或特性的例程、结束例程】
  14. 使用IDEA开发Android程序(二)第一个简单的程序并运行
  15. 四、OSPF配置实验
  16. The Art Of Code-Beta
  17. 深度学习方法在糖尿病视网膜病变诊断中的应用
  18. Quality Assurance (质量保证)
  19. luajit的字节码
  20. 格里高利历java_java – 从Hijri日期字符串中获取格里高利日期

热门文章

  1. 终极解决MySql: java.sql.SQLException: Incorrect string value: ‘\xF0\x9F\x8C\x9D\xF0\x9F...‘ for column
  2. cad捕捉不到标注线上的点_我的CAD,突然画线,标注时 放大了捕捉点总是捕捉不到,而且老是在跳!不听使唤那种?怎么回事?这是?...
  3. list-style与list-style-type的区别
  4. 25岁转行UI,到底可不可以?
  5. CentOS安装mysql 5.7.28
  6. python supper函数_第四节: 字符串魔法功能
  7. java 代码打开jar文件_Java基础之用记事本编辑java代码运行,并且打成jar包后运行...
  8. PHP对接达达平台步骤
  9. 骑战三国服务器维护,《骑战三国》4月26日进行全服停服更新
  10. oracle 中累加函数,CSS_oracle使用sum函数进行累加计算,====================Question============ - phpStudy...