用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下申明对象的几种方法小结
Oct 02 Javascript
比Jquery的document.ready更快的方法
Apr 28 Javascript
json对象转字符串如何实现
Dec 02 Javascript
JS代码同步文本框内容的实例方法
Jul 12 Javascript
javascript 按键事件(兼容各浏览器)
Dec 20 Javascript
js修改原型的属性使用介绍
Jan 26 Javascript
js判断某个方法是否存在实例代码
Jan 10 Javascript
动态加载jQuery的两种方法实例分析
Jul 17 Javascript
Bootstrap每天必学之轮播(Carousel)插件
Apr 25 Javascript
Vue.js 2.0窥探之Virtual DOM到底是什么?
Feb 10 Javascript
element-ui中的select下拉列表设置默认值方法
Aug 24 Javascript
Vue环境搭建+VSCode+Win10的详细教程
Aug 19 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/22 PHP
探讨:如何编写PHP扩展
2013/06/13 PHP
Linux环境下搭建php开发环境的操作步骤
2013/06/17 PHP
phpmyadmin出现Cannot start session without errors问题解决方法
2014/08/14 PHP
php设计模式之正面模式实例分析【星际争霸游戏案例】
2020/03/24 PHP
jQuery 插件 将this下的div轮番显示
2009/04/09 Javascript
ExtJS 2.0实用简明教程 之ExtJS版的Hello
2009/04/29 Javascript
兼容IE与firefox火狐的回车事件(js与jquery)
2010/10/20 Javascript
深入理解JavaScript系列(14) 作用域链介绍(Scope Chain)
2012/04/12 Javascript
jQuery之按钮组件的深入解析
2013/06/19 Javascript
基于jQuery实现的图片切换焦点图整理
2014/12/07 Javascript
简介JavaScript中的unshift()方法的使用
2015/06/09 Javascript
javascript简单判断输入内容是否合法的方法
2016/05/11 Javascript
nodejs中模块定义实例详解
2017/03/18 NodeJs
在Python中操作时间之tzset()方法的使用教程
2015/05/22 Python
在PyCharm中实现关闭一个死循环程序的方法
2018/11/29 Python
Python给定一个句子倒序输出单词以及字母的方法
2018/12/20 Python
python 定时器,实现每天凌晨3点执行的方法
2019/02/20 Python
Python eval的常见错误封装及利用原理详解
2019/03/26 Python
Python TCPServer 多线程多客户端通信的实现
2019/12/31 Python
浅谈python之自动化运维(Paramiko)
2020/01/31 Python
浅谈Pycharm最有必要改的几个默认设置项
2020/02/14 Python
Python解析微信dat文件的方法
2020/11/30 Python
浅谈html5之sse服务器发送事件EventSource介绍
2017/08/28 HTML / CSS
毕业生应聘幼儿园的自荐信
2013/11/20 职场文书
服装公司总经理岗位职责
2013/11/30 职场文书
会计大学生职业生涯规划书范文
2014/01/13 职场文书
KTV的创业计划书范文
2014/02/02 职场文书
小学英语课后反思
2014/04/26 职场文书
中学生关于梦想的演讲稿
2014/08/22 职场文书
中学感恩教育活动总结
2015/05/05 职场文书
2016年小学生寒假总结
2015/10/10 职场文书
《夸父追日》教学反思
2016/02/20 职场文书
selenium.webdriver中add_argument方法常用参数表
2021/04/08 Python
浅谈PHP7中的一些小技巧
2021/05/29 PHP
MySQL中正则表达式(REGEXP)使用详解
2022/07/07 MySQL