用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中的push和join方法使用介绍
Oct 08 Javascript
简单实用的全选反选按钮例子
Oct 18 Javascript
JS控制图片等比例缩放的示例代码
Dec 24 Javascript
jquery关于事件冒泡和事件委托的技巧及阻止与允许事件冒泡的三种实现方法
Nov 27 Javascript
JavaScript对象参数的引用传递
Jan 14 Javascript
Javascript基础_嵌入图像的简单实现
Jun 14 Javascript
微信小程序 基础组件与导航组件详细介绍
Feb 21 Javascript
jQuery滚动监听实现商城楼梯式导航效果
Mar 06 Javascript
如何使用Bootstrap 按钮实例详解
Mar 29 Javascript
Bootstrap栅格系统的使用详解
Oct 30 Javascript
浅谈js闭包理解
Apr 01 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 jQuery
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设计模式 Template (模板模式)
2011/06/26 PHP
php中call_user_func函数使用注意事项
2014/11/21 PHP
PHP MVC框架skymvc支持多文件上传
2016/05/26 PHP
PHP从零开始打造自己的MVC框架之类的自动加载实现方法详解
2019/06/03 PHP
Jquery跳到页面指定位置的方法
2014/05/12 Javascript
Jquery对象和Dom对象的区别分析
2014/11/20 Javascript
在JavaScript中操作时间之getMonth()方法的使用
2015/06/10 Javascript
jQuery1.9+中删除了live以后的替代方法
2016/06/17 Javascript
Vue父组件调用子组件事件方法
2018/02/23 Javascript
vue3.0 CLI - 2.3 - 组件 home.vue 中学习指令和绑定
2018/09/14 Javascript
Angularjs实现数组随机排序的方法
2018/10/02 Javascript
js前端面试之同步与异步问题详解
2019/04/03 Javascript
微信小程序中限制激励式视频广告位显示次数(实现思路)
2019/12/06 Javascript
如何优雅地取消 JavaScript 异步任务
2020/03/22 Javascript
JS实现单张或多张图片持续无缝滚动的示例代码
2020/05/10 Javascript
Openlayers实现点闪烁扩散效果
2020/09/24 Javascript
python模拟表单提交登录图书馆
2018/04/27 Python
pandas 对series和dataframe进行排序的实例
2018/06/09 Python
Python中循环后使用list.append()数据被覆盖问题的解决
2018/07/01 Python
Django框架实现的简单分页功能示例
2018/12/04 Python
使用python将图片按标签分入不同文件夹的方法
2018/12/08 Python
Python实战之制作天气查询软件
2019/05/14 Python
Python OrderedDict的使用案例解析
2019/10/25 Python
python thrift 实现 单端口多服务的过程
2020/06/08 Python
对python pandas中 inplace 参数的理解
2020/06/27 Python
如何在mac版pycharm选择python版本
2020/07/21 Python
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
巴西男士个人护理产品商店:SHOP4MEN
2017/08/07 全球购物
写好自荐信的几个要点
2013/12/26 职场文书
《一个中国孩子的呼声》教学反思
2014/02/12 职场文书
结婚喜宴主持词
2014/03/14 职场文书
陈欧的广告词
2014/03/18 职场文书
公司租车协议书
2015/01/29 职场文书
个人求职信格式范文
2015/03/20 职场文书
2016师德师风学习心得体会
2016/01/12 职场文书
Spark SQL 2.4.8 操作 Dataframe的两种方式
2021/10/16 SQL Server