用react实现todoList

533 阅读2分钟

一前言

刚开始入门Vue的时候,是通过编写todoList入门的,同样,入门React,也通过react+antd编写一个简单的todoList小Demo,熟悉React的基本语法和开发流程。

二程序功能

  • 显示当前的任务
  • 加入/删除任务
  • 可以将任务标记为已完成/未完成

三创建项目

  1. 下载Node.js
  2. 安装React脚手架
    • npm i create-react-app -g 如果你以前全局安装过,可以忽略当前操作
    • create-react-app todolist
    • cd todolist
    • npm i antd -S
    • npm start
  3. 打开localhost:3000 查看页面,显示如下,表示成功启动。

四正文

  • 4.1 引入sass
    • 以前用vue-cli脚手架的时候,只需要引入sass的相关依赖即可。但是在crate-react-app,除了引入sass依赖 npm i sass-loader node-sass -S 之外,还需要进行额外的配置:在node_modules/react-scripts/config/webpapack.config.js 文件下,在module配置项的最后一添加:
    {
        test: '/\.scss$/', loaders: ['style-loader', 'scs-loader', 'sass-loader']
     }
    
  • 4.2 引入css模块化
    • css的规则都是全局的,任何一个组件的样式规则,都对整个页面有效。

    • 所以在Vue中,我们为了避免组件样式全局污染,框架给我们提供了一个scoped的选项。通过如下定义: <style scoped> ... </style> 我们可以避免不同组件之间的样式污染, 但是在React中是不存在这个选项的。React则是通过 css module 来防止对不同组件的全局样式污染。

    • 其实在create-react-app中内置了css Module的配置,我们只需将所有的..css/.scss/.less等样式文件都修改成.module.css/.module.scss/.module.less, 然后在jsx文件中使用import的方式将其引入。

      import styled from './App.module.scss'
      <div className={styled.wrapper}>
       </div>
      
    审查元素:

可以看到生成的类名是独一无二的,和Vue中scoped原理是一样的。

  • 4.3 功能代码
import React, {Component, Fragment} from 'react';

import { Input, List , Checkbox } from 'antd'
import styled from './App.module.scss'


const {Search} = Input
class App extends Component {
  constructor (props) {
    super(props);
    this.state = {
      value: '',
      list: [
        {
          title: '吃饭',
          id: 1,
          isCompleted: false
        },
        {
          title: '睡觉',
          id: 2,
          isCompleted: false
        },
        {
          title: '打豆豆',
          id: 3,
          isCompleted: true
        }
      ]
    }
  }

  render () {
    return (
      <div className={styled.wrapper}>
        <h2>Todo-List</h2>
        <Search
          placeholder="请输入关键字~~"
          enterButton="添加"
          size="large"
          allowClear
          value={this.state.value}
          onChange={this.handleChange}
          onPressEnter={this.handlePressEnter}
          onSearch={this.handleAdd}
        />
        <List
          bordered
          className={styled.gaosen}
          dataSource={this.state.list}
          renderItem={(item, index) => <List.Item className={styled['list-item']}>
              <Fragment>
                <Checkbox checked={item.isCompleted} onChange={this.handleCheckChange.bind(this,item.id)}></Checkbox>
                <span className={item.isCompleted ? styled['line-through'] : ''}>{item.title}</span>
              </Fragment>
              <span style={{color:'red'}} onClick={this.handleDelete.bind(this, item, index)}>删除</span>
          </List.Item>}
        />
      </div>

    );
  }
  // 改变选中状态
  handleCheckChange (id) {
    this.setState((prevState) => {
      console.log(prevState)
      return {
        list: prevState.list.map(todo => {
          if (todo.id === id) {
            todo.isCompleted = !todo.isCompleted
          }
          return todo
        })
      }
    })
  }
  // 回车
  handlePressEnter = () => {
    this.handleAdd(this.state.value)
  }
  // change
  handleChange = (e) => {
    const value = e.target.value
    this.setState({
      value
    })
  }
  // delete
  handleDelete (item, index, e) {
    let newList = JSON.parse(JSON.stringify(this.state.list))
    newList.splice(index, 1)
    this.setState({
      list: newList
    })
  }
  // add
  handleAdd = (title) => {
    if (!title) return
    let copy = [...this.state.list, {title}]
    this.setState({
      list: copy,
      value: ''
    }, () => {
    })
  }
}

export default App;

  • 4.4 页面效果