用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 相关文章推荐
Javascript模块化编程(三)require.js的用法及功能介绍
Jan 17 Javascript
JavaScript动态创建div属性和样式示例代码
Oct 09 Javascript
Javascript 运动中Offset的bug解决方案
Dec 24 Javascript
javacript使用break内层跳出外层循环分析
Jan 12 Javascript
超级给力的JavaScript的React框架入门教程
Jul 02 Javascript
javascript基本语法
May 31 Javascript
JavaScript原生编写《飞机大战坦克》游戏完整实例
Jan 04 Javascript
jQuery 全选 全不选 事件绑定的实现代码
Jan 23 Javascript
Ionic3 UI组件之autocomplete详解
Jun 08 Javascript
使用js实现将后台传入的json数据放在前台显示
Aug 06 Javascript
解决 viewer.js 动态更新图片导致无法预览的问题
May 14 Javascript
React 全自动数据表格组件——BodeGrid的实现思路
Jun 12 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显示时间常用方法小结
2015/06/05 PHP
PHP中spl_autoload_register()函数用法实例详解
2016/07/18 PHP
详解json在php中的应用
2018/09/30 PHP
nw.js实现类似微信的聊天软件
2015/03/16 Javascript
Bootstrap学习笔记之css样式设计(1)
2016/06/07 Javascript
bootstrap datetimepicker实现秒钟选择下拉框
2017/01/05 Javascript
Vue.js基础学习之class与样式绑定
2017/03/20 Javascript
js实现本地时间同步功能
2017/08/26 Javascript
vue使用xe-utils函数库的具体方法
2018/03/06 Javascript
深入学习Vue nextTick的用法及原理
2019/10/08 Javascript
JavaScript多种图形实现代码实例
2020/06/28 Javascript
[54:51]Ti4 冒泡赛第二轮LGD vs C9 3
2014/07/14 DOTA
[03:36]2014DOTA2 TI小组赛综述 八强诞生进军钥匙球馆
2014/07/15 DOTA
Python中使用strip()方法删除字符串中空格的教程
2015/05/20 Python
python删除过期log文件操作实例解析
2018/01/31 Python
在Python中使用gRPC的方法示例
2018/08/08 Python
在mac下查找python包存放路径site-packages的实现方法
2018/11/06 Python
Pandas删除数据的几种情况(小结)
2019/06/21 Python
Django框架静态文件使用/中间件/禁用ip功能实例详解
2019/07/22 Python
python多进程下的生产者和消费者模型
2020/05/07 Python
Python timeit模块原理及使用方法
2020/10/10 Python
CSS3 边框效果
2019/11/04 HTML / CSS
The Hut德国站点:时装、家居用品、美容等
2016/09/23 全球购物
中国高端鲜花第一品牌:roseonly(一生只送一人)
2017/02/12 全球购物
Foot Locker澳洲官网:美国运动服和鞋类零售商
2019/10/11 全球购物
UNIX文件名称有什么规定
2013/03/25 面试题
魅力教师事迹材料
2014/01/10 职场文书
联谊活动策划书
2014/01/26 职场文书
揭牌仪式策划方案
2014/05/28 职场文书
2014最新版群众路线四风整改措施
2014/09/24 职场文书
群众路线教育党员自我剖析材料
2014/10/06 职场文书
买房协议书范本
2014/10/23 职场文书
标准离婚协议书范文下载
2014/11/30 职场文书
2016春节慰问信范文
2015/03/25 职场文书
详解运行Python的神器Jupyter Notebook
2021/06/03 Python
详解如何用Python实现感知器算法
2021/06/18 Python