用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解决常见浏览器兼容问题的12种方法
Jan 04 Javascript
真正的JQuery.ajax传递中文参数的解决方法
May 28 Javascript
jQuery中map()方法用法实例
Jan 06 Javascript
jquery编写Tab选项卡滚动导航切换特效
Jul 17 Javascript
wap手机端解决返回上一页的js实例
Dec 08 Javascript
探索Javascript中this的奥秘
Dec 11 Javascript
浅谈react前后端同构渲染
Sep 20 Javascript
详解webpack引入第三方库的方式以及注意事项
Jan 15 Javascript
微信小程序实现展示评分结果功能
Feb 15 Javascript
JavaScript数组去重实现方法小结
Jan 17 Javascript
js布局实现单选按钮控件
Jan 17 Javascript
JavaScript正则表达式验证登录实例
Mar 18 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学习之php4与php5之间会穿梭一点点感悟
2007/05/03 PHP
CentOS下PHP安装Oracle扩展
2015/02/15 PHP
PHP通过CURL实现定时任务的图片抓取功能示例
2016/10/03 PHP
删除PHP数组中头部、尾部、任意元素的实现代码
2017/04/10 PHP
使用iframe window的scroll方法控制iframe页面滚动
2014/03/05 Javascript
巧用replace将文字表情替换为图片
2014/04/17 Javascript
jquery操作 iframe的方法
2014/12/03 Javascript
javascript实现仿IE顶部的可关闭警告条
2015/05/05 Javascript
js从外部获取图片的实现方法
2016/08/05 Javascript
javascript常用的设计模式
2017/02/09 Javascript
详解vue-router 2.0 常用基础知识点之router.push()
2017/05/10 Javascript
jQuery实现切换隐藏与显示同时切换图标功能
2017/10/29 jQuery
讲解vue-router之什么是嵌套路由
2018/05/28 Javascript
基于jQuery的时间戳与日期间的转化
2019/06/21 jQuery
Vue组件通信入门之Provide和Inject机制
2019/12/29 Javascript
nuxt.js 在middleware(中间件)中实现路由鉴权操作
2020/11/06 Javascript
[01:03]悬念揭晓 11月26日DOTA2完美盛典不见不散
2017/11/23 DOTA
基于Python实现一个简单的银行转账操作
2016/03/06 Python
Python多维/嵌套字典数据无限遍历的实现
2016/11/04 Python
Python入门_条件控制(详解)
2017/05/16 Python
基于python实现从尾到头打印链表
2019/11/02 Python
Python中pyecharts安装及安装失败的解决方法
2020/02/18 Python
Python实现队列的方法示例小结【数组,链表】
2020/02/22 Python
python + selenium 刷B站播放量的实例代码
2020/06/12 Python
Django通过设置CORS解决跨域问题
2020/11/26 Python
python中reload重载实例用法
2020/12/15 Python
前端面试必备之html5的新特性
2017/09/05 HTML / CSS
使用Canvas操作像素的方法
2018/06/14 HTML / CSS
乌克兰在线药房:Аптека24
2019/10/30 全球购物
建筑工程管理专业自荐信范文
2013/12/28 职场文书
公司年会策划方案
2014/05/17 职场文书
自强自立美德少年事迹材料
2014/08/16 职场文书
党员个人剖析材料2014
2014/10/08 职场文书
作风转变年心得体会
2014/10/22 职场文书
2014年乡镇卫生院工作总结
2014/11/24 职场文书
师德师风主题教育活动总结
2015/05/07 职场文书