用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自动显示最后更新时间
Mar 15 Javascript
jQuery 版元素拖拽原型代码
Apr 25 Javascript
用JQUERY增删元素的代码
Feb 14 Javascript
实现只能输入数字的input不用replace方法
Sep 12 Javascript
基于jQuery实现网页打印功能
Dec 01 Javascript
jQuery搜索框效果实现代码(百度关键词联想)
Feb 25 Javascript
js获取json中key所对应的value值的简单方法
Jun 17 Javascript
vue-router项目实战总结篇
Feb 11 Javascript
详解Puppeteer 入门教程
May 09 Javascript
浅析JavaScript异步代码优化
Mar 18 Javascript
mpvue性能优化实战技巧(小结)
Apr 17 Javascript
vue打包时去掉所有的console.log
Apr 10 Vue.js
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实现分页的一个示例
2006/10/09 PHP
我的论坛源代码(八)
2006/10/09 PHP
PHP中数据库单例模式的实现代码分享
2014/08/21 PHP
PHP 前加at符合@的作用解析
2015/07/31 PHP
在WordPress的后台中添加顶级菜单和子菜单的函数详解
2016/01/11 PHP
php判断用户是否关注微信公众号
2016/07/22 PHP
PHP7下协程的实现方法详解
2017/12/17 PHP
php swoole多进程/多线程用法示例【基于php7nts版】
2019/08/12 PHP
jQuery判断元素是否是隐藏的代码
2011/04/24 Javascript
JS中产生20位随机数以0-9为例也可以是a-z A-Z
2014/08/01 Javascript
jQuery的load()方法及其回调函数用法实例
2015/03/25 Javascript
Angular2表单自定义验证器的实现
2016/10/19 Javascript
JavaScript利用正则表达式替换字符串中的内容
2016/12/12 Javascript
jQuery制作图片旋转效果
2017/02/02 Javascript
Bootstrap modal 多弹窗之叠加关闭阴影遮罩问题的解决方法
2017/02/27 Javascript
解决jQuery ajax动态新增节点无法触发点击事件的问题
2017/05/24 jQuery
微信小程序开发之toast提示插件使用示例
2017/06/08 Javascript
从vue源码解析Vue.set()和this.$set()
2018/08/30 Javascript
Bootstrap4 gulp 配置详解
2019/01/06 Javascript
Vue动态修改网页标题的方法及遇到问题
2019/06/09 Javascript
纯js+css实现仿移动端淘宝网站的弹出详情框功能
2019/12/29 Javascript
使用Python实现下载网易云音乐的高清MV
2015/03/16 Python
利用Python的Twisted框架实现webshell密码扫描器的教程
2015/04/16 Python
将Python代码打包为jar软件的简单方法
2015/08/04 Python
教你使用python画一朵花送女朋友
2018/03/29 Python
matplotlib 输出保存指定尺寸的图片方法
2018/05/24 Python
Python3多目标赋值及共享引用注意事项
2019/05/27 Python
pytorch实现mnist分类的示例讲解
2020/01/10 Python
java关于string最常出现的面试题整理
2021/01/18 Python
仿CSDN Blog返回页面顶部功能实现原理及代码
2013/06/30 HTML / CSS
美国健康和保健平台:healtop
2020/07/02 全球购物
本科生详细的自我评价
2013/09/19 职场文书
教师年度考核评语
2014/04/28 职场文书
财务工作检讨书
2014/10/29 职场文书
同学联谊会邀请函
2019/06/24 职场文书
(开源)微信小程序+mqtt,esp8266温湿度读取
2021/04/02 Javascript