用React实现一个完整的TodoList的示例代码


Posted in Javascript onOctober 30, 2017

前言:算起来已经有一个多月没有写博客了,近来懈怠了不少,也不知道要写些什么,最近学了一段时间的React,一直都在看些理论性的知识,总觉得应该写个什么来练练手,所以还是拿个简单的todoList来举个例子吧!

一. 首先根据效果图讲一下要实现的功能吧

用React实现一个完整的TodoList的示例代码

todoList最终效果图

(1)可以添加任务;
(2)已完成任务以及未完成任务的颜色区分开;
(3)进行添加任务,修改任务状态,以及删除任务时,下面的任务完成数目和任务总数要进行变化;

以上就是要实现的功能。

二. 接下来该如何设计呢?

(1)任务存储的数据结构:

list: [{
      id: 0,
      name: '吃饭',
      status: 0
    }, {
      id: 1,
      name: '睡觉',
      status: 0
    }, {
      id: 2,
      name: '打豆豆',
      status : 0
    }]

每个任务都有自己的id,任务名,以及任务的状态,任务的id除了标识任务的唯一性,还可以作为列表项的key值。我们都知道在react中使用列表,列表的每一项必须有个key值,这样会使得每个列表项可以快速定位,在执行Diff算法时减少不必要的查询,从而对性能的提升有所帮助。

(2)组件的划分

  1. TodoList整体作为一个大组件;
  2. 列表中的每个列表项(ListItem)作为一个组件;
  3. 任务的添加框(Dialog)作为一组件。

三. 具体实现

以列表项ListItem的实现为例:

将列表项单独划分为一个组件是必须的,这样使得每个单独的条目都是独立的,使得代码的逻辑更加简单,增强代码的复用性,维护也会变得更简单。

当然聪明的你肯定会想到一个问题:每一个Task的状态改变或者Task的添加删除,Task的完成数目和总数目都是会改变的,可是每个ListItem都是相互独立的,如何实现呢?这时就要用到父子组件之间的通信了。

如果你也是和我一样React的初学者,百度一下就会出现很多文章都会讲父子组件间如何通信,下面我简单说一下自己简单粗暴的理解:

在父子组件中定义改变state数据的方法,将方法以props的形式传递给子组件,在子组件中触发事件处理程序,然后满足某种条件的话就执行父组件传来的函数。

具体代码如下:

父组件中的代码:

import React, { Component } from 'react';
import ListItem from './listItem';
import Dialog from './dialog';
import './main.css';

class TodoList extends Component {
  constructor (props) {
    super(props);
    
    //初始任务列表
    this.state = {
      list: [{
        id: 0,
        name: '吃饭',
        status: 0
      }, {
        id: 1,
        name: '睡觉',
        status: 0
      }, {
        id: 2,
        name: '打豆豆',
        status : 0
      }],
      finished: 0
    };
  }
  
  //添加新任务,在组件中以props的形式传递给子组件
  addTask (newitem) {
    var allTask = this.state.list;
    allTask.push(newitem);
    this.setState({
      list: allTask
    });
  }
  //更新完成的任务,在组件中以props的形式传递给子组件
  updateFinished (todoItem) {
    var sum = 0;
    this.state.list.forEach( (item) => {
      if (item.id === todoItem.id) {
        item.status = todoItem.status;
      }
      if (item.status === 1) {
        sum++;
      }
    });
    this.setState({
      finished: sum
    });
  }

  //更新任务总数,在组件中以props的形式传递给子组件
  updateTotal (todoItem) {
    var obj = [], sum = 0;
    this.state.list.forEach((item) => {
      if (item.id !== todoItem.id) {
        obj.push(item);
        if (item.status === 1 ) {
          sum++;
        }
      }
    });
    this.setState({
      list: obj,
      finished: sum
    });
  }

  render () {
    return (
      <div className="container">
        <h1>TodoList</h1>
        <ul>
          { this.state.list.map ((item, index) =>
            <ListItem 
              item={item} 
              finishedChange={this.updateFinished.bind(this)} 
              totalChange={this.updateTotal.bind(this)}
              key={index}
            />
          )}
          <li>{this.state.finished}已完成 / {this.state.list.length}总数</li>
        </ul>
        <Dialog addNewTask={this.addTask.bind(this)} nums={this.state.list.length}/>
      </div>
    );
  }
}

export default TodoList;

子组件中的代码:

import React, { Component } from 'react';

class ListItem extends Component {
  constructor (props) {
    super(props);

    this.handleFinished = this.handleFinished.bind(this);
    this.handleDelete = this.handleDelete.bind(this);
  } 

  handleFinished () {
    var status = this.props.item.status;

    status = (status === 0 ? 1 : 0);

    var obj = {
      id: this.props.item.id,
      name: this.props.item.name,
      status: status
    }
    
    this.props.finishedChange(obj); //执行父组件传来的方法
  }

  handleDelete () {
    this.props.totalChange(this.props.item); //执行父组件传来的方法
  }

  render () {
    const item = this.props.item;

    const unfinish = {
      backgroundColor: '#DFFCB5',
      color: '#2EB872',
    };

    const finish = {
      backgroundColor: '#FFFA9D',
      color: '#FF9A3C',
      textDecoration: 'line-through'
    }

    var itemStyle = item.status === 0 ? unfinish : finish;
    
    return (
      <li key={item.id} style={itemStyle}>
        <span 
          onClick={this.handleFinished} 
          id={item.id}
          className="check-btn"
          style={{backgroundColor: item.status === 0 ? '#fff' : '#A1EAFB'}}
        ></span>
        <span>{ item.name }</span>
        <span onClick={this.handleDelete} className="delete-btn">删除</span>
      </li>
    );
  }
}

export default ListItem;

以上是对这个小练习的一个总结,如果你也和我一样是个react新手的话,写完这个相信你对React一定会有更近一步的理解,小练习以上传至github,可以进行参考哦!希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Prototype Array对象 学习
Jul 19 Javascript
JavaScript 常用函数
Dec 30 Javascript
javascript 使td内容不换行不撑开
Nov 29 Javascript
表单元素的submit()方法和onsubmit事件应用概述
Feb 01 Javascript
smartupload实现文件上传时获取表单数据(推荐)
Dec 12 Javascript
js 获取html5的data属性实现方法
Jul 28 Javascript
关于Vue实现组件信息的缓存问题
Aug 23 Javascript
JS跳转手机站url的若干注意事项
Oct 18 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
Apr 18 Javascript
javascript实现遮罩层动态效果实例
May 14 Javascript
150行Node.js实现的dns代理工具
Aug 02 Javascript
如何在面试中手写出javascript节流和防抖函数
Oct 22 Javascript
JavaScript实现精美个性导航栏筋斗云效果
Oct 29 #Javascript
vue中的scope使用详解
Oct 29 #Javascript
Vue.js划分组件的方法
Oct 29 #Javascript
vue.js  父向子组件传参的实例代码
Oct 29 #Javascript
vue.js todolist实现代码
Oct 29 #Javascript
javascript按钮禁用和启用的效果实例代码
Oct 29 #Javascript
jQuery实现切换隐藏与显示同时切换图标功能
Oct 29 #jQuery
You might like
10个可以简化php开发过程的MySQL工具
2010/04/11 PHP
PHP输出数组中重名的元素的几种处理方法
2012/09/05 PHP
PHP、Python和Javascript的装饰器模式对比
2015/02/03 PHP
Zend Framework分页类用法详解
2016/03/22 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
PHP获取当前URL路径的处理方法(适用于多条件筛选列表)
2017/02/10 PHP
使用Javascript和DOM Interfaces来处理HTML
2006/10/09 Javascript
Javascript 构造函数,公有,私有特权和静态成员定义方法
2009/11/30 Javascript
JSON辅助格式化处理方法
2013/03/26 Javascript
animate动画示例(泪奔的小孩)及stop和delay的使用
2013/05/06 Javascript
javascript中数组的sort()方法的使用介绍
2013/12/18 Javascript
超实用的JavaScript代码段 附使用方法
2016/05/22 Javascript
jQuery实现下拉框多选 jquery-multiselect 的实例代码
2016/07/14 Javascript
AngularJS 依赖注入详解和简单实例
2016/07/28 Javascript
Express与NodeJs创建服务器的两种方法
2017/02/06 NodeJs
js中的DOM模拟购物车功能
2017/03/22 Javascript
JQuery 获取多个select标签option的text内容(实例)
2017/09/07 jQuery
浅谈vuex的基本用法和mapaction传值问题
2019/11/08 Javascript
使用Python编写一个简单的tic-tac-toe游戏的教程
2015/04/16 Python
Python的Django框架中if标签的相关使用
2015/07/15 Python
Python求平面内点到直线距离的实现
2020/01/19 Python
flask框架渲染Jinja模板与传入模板变量操作详解
2020/01/25 Python
结束运行python的方法
2020/06/16 Python
Python ellipsis 的用法详解
2020/11/20 Python
台湾乐天市场:日本No.1的网路购物网站
2017/03/22 全球购物
Charles & Keith欧盟:新加坡时尚品牌
2019/08/01 全球购物
统计每一学生的平均成绩
2014/06/06 面试题
如何查看在weblogic中已经发布的EJB
2012/06/01 面试题
有abstract方法的类一定要用abstract修饰吗
2016/03/14 面试题
人力资源管理专业毕业生自我评价
2013/09/21 职场文书
货代行业个人求职简历的自我评价
2013/10/22 职场文书
实用求职信范文分享
2013/12/25 职场文书
解除劳动合同协议书范本
2014/09/13 职场文书
2015幼儿园庆元旦活动方案
2014/12/09 职场文书
会议开幕词
2015/01/28 职场文书
pygame面向对象的飞行小鸟实现(Flappy bird)
2021/04/01 Python