用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 相关文章推荐
Cookie 小记
Apr 01 Javascript
javascript预览上传图片发现的问题的解决方法
Nov 25 Javascript
收集的一些Array及String原型对象的扩展实现代码
Dec 05 Javascript
JQuery 实现在同一页面锚点链接之间的平滑滚动
Oct 29 Javascript
jquery使用经验小结
May 20 Javascript
IE浏览器下PNG相关功能
Jul 05 Javascript
javascript设置页面背景色及背景图片的方法
Dec 29 Javascript
Bootstrap被封装的弹层
Jul 20 Javascript
AngularJS延迟加载html template
Jul 27 Javascript
Node.js中防止错误导致的进程阻塞的方法
Aug 11 Javascript
Vue 中获取当前时间并实时刷新的实现代码
May 12 Javascript
js仿京东放大镜效果
Aug 09 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
PHP 代码规范小结
2012/03/08 PHP
PHP is_array() 检测变量是否是数组的实现方法
2016/06/13 PHP
JsEasy简介 JsEasy是什么?与下载
2007/03/07 Javascript
ASP中用Join和Array,可以加快字符连接速度的代码
2007/08/22 Javascript
js不完美解决click和dblclick事件冲突问题
2012/07/16 Javascript
js 对小数加法精度处理示例说明
2013/12/27 Javascript
js+css实现的简单易用兼容好的分页
2013/12/30 Javascript
jquery常用特效方法使用示例
2014/04/25 Javascript
深入学习JavaScript中的Rest参数和参数默认值
2015/07/28 Javascript
JavaScript图片轮播代码分享
2015/07/31 Javascript
json传值以及ajax接收详解
2016/05/24 Javascript
jQuery模拟完美实现经典FLASH导航动画效果【附demo源码下载】
2016/11/09 Javascript
vue组件 $children,$refs,$parent的使用详解
2017/07/31 Javascript
详解如何将 Vue-cli 改造成支持多页面的 history 模式
2017/11/20 Javascript
如何从零开始利用js手写一个Promise库详解
2018/04/19 Javascript
jQuery实现table表格checkbox全选的方法分析
2018/07/04 jQuery
Mint-UI时间组件起始时间问题及时间插件使用
2018/08/20 Javascript
详解vue-cli+es6引入es5写的js(两种方法)
2019/04/19 Javascript
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
JS快速实现简单计算器
2020/04/08 Javascript
Vue实现简单的跑马灯
2020/05/25 Javascript
node.js通过Sequelize 连接MySQL的方法
2020/12/28 Javascript
python实现基于两张图片生成圆角图标效果的方法
2015/03/26 Python
详解Python中列表和元祖的使用方法
2015/04/25 Python
使用Python编写提取日志中的中文的脚本的方法
2015/04/30 Python
利用Python破解斗地主残局详解
2017/06/30 Python
Python管理Windows服务小脚本
2018/03/12 Python
django+echart绘制曲线图的方法示例
2018/11/26 Python
Python 列表的清空方式
2020/01/13 Python
python爬虫scrapy基于CrawlSpider类的全站数据爬取示例解析
2021/02/20 Python
漫威玩具服装及周边商品官方购物网站:Marvel Shop
2019/05/11 全球购物
Shell如何接收变量输入
2016/08/06 面试题
个人实习生的自我评价
2014/02/16 职场文书
农民工工资承诺书范文
2014/03/31 职场文书
经济贸易系求职信
2014/08/04 职场文书
乡镇党的群众路线教育实践活动个人整改方案
2014/10/31 职场文书