用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 相关文章推荐
根据出生日期自动取得星座的js代码
Jul 20 Javascript
基于jquery的自定义鼠标提示效果 jquery.toolTip
Nov 14 Javascript
jquery.tmpl JQuery模板插件
Oct 10 Javascript
JQuery.closest(),parent(),parents()寻找父结点
Feb 17 Javascript
为jQuery添加Webkit的触摸的方法分享
Feb 02 Javascript
对js关键字命名的疑问介绍
Apr 25 Javascript
JSONP之我见
Mar 24 Javascript
详解webpack2+React 实例demo
Sep 11 Javascript
微信小程序实现滑动切换自定义页码的方法分析
Dec 29 Javascript
微信小程序实现左侧滑动导航栏
Apr 08 Javascript
js前端如何写一个精确的倒计时代码
Oct 25 Javascript
vue中使用vue-print.js实现多页打印
Mar 05 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
ezSQL PHP数据库操作类库
2010/05/16 PHP
PHP调用Webservice实例代码
2011/07/29 PHP
微信公众平台之快递查询功能用法实例
2015/04/14 PHP
Zend Framework动作助手Redirector用法实例详解
2016/03/05 PHP
PHP中include/require/include_once/require_once使用心得
2016/08/28 PHP
php生成毫秒时间戳的实例讲解
2017/09/22 PHP
PHP排序二叉树基本功能实现方法示例
2018/05/26 PHP
phpstudy2020搭建站点的实现示例
2020/10/30 PHP
div层的移动及性能优化
2010/11/16 Javascript
js图片模糊切换显示特效的方法
2015/02/17 Javascript
Backbone.js的Hello World程序实例
2015/06/19 Javascript
javascript实现网页子页面遍历回调的方法(涉及 window.frames、递归函数、函数上下文)
2015/07/27 Javascript
基于Jquery和html5的7款个性化地图插件
2015/11/17 Javascript
js判断手机访问或者PC的几个例子(常用于手机跳转)
2015/12/15 Javascript
AngularJS基础 ng-switch 指令简单示例
2016/08/03 Javascript
jQuery源码分析之init的详细介绍
2017/02/13 Javascript
JS传参及动态修改页面布局
2017/04/13 Javascript
微信小程序多张图片上传功能
2017/06/07 Javascript
详解vue 计算属性与方法跟侦听器区别(面试考点)
2018/04/23 Javascript
JavaScript模块管理的简单实现方式详解
2019/06/15 Javascript
layui 数据表格 点击分页按钮 监听事件的实例
2019/09/02 Javascript
Python基础学习之函数方法实例详解
2019/06/18 Python
详解Python Qt的窗体开发的基本操作
2019/07/14 Python
Pytorch中的variable, tensor与numpy相互转化的方法
2019/10/10 Python
python 实现线程之间的通信示例
2020/02/14 Python
python 瀑布线指标编写实例
2020/06/03 Python
为什么说python更适合树莓派编程
2020/07/20 Python
python sleep和wait对比总结
2021/02/03 Python
html5适合移动应用开发的12大特性
2014/03/19 HTML / CSS
解决HTML5中的audio在手机端和微信端的不能自动播放问题
2019/11/04 HTML / CSS
一套中级Java程序员笔试题
2015/01/14 面试题
社区包粽子活动方案
2014/01/21 职场文书
《罗布泊,消逝的仙湖》教学反思
2014/03/01 职场文书
机关单位人员学雷锋心得体会
2014/03/10 职场文书
500字作文之周记
2019/12/13 职场文书
Python实现随机生成迷宫并自动寻路
2021/06/13 Python