zoukankan      html  css  js  c++  java
  • 菜鸟程序员的react TodoList练习之旅

    前言

    hello 大家好,我是一个菜鸟程序员,都说学习前端框架大多从 TodoList 学起,我呢,学习 react 也有一段时间了,特此做了一个 TodoList 做为自己的学习总结,顺便发个博客记录一下自己的学习,如有错漏欢迎大神在评论区指点。

    环境安装

    注意

    第一行的 npx 不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。

    npx create-react-app my-app
    cd my-app
    

    删除掉新项目中 src/ 文件夹下的所有文件,并新建二个文件,index.js 和 index.css.

    安装 antd,使用 UI 框架让我们的 TodoList 更加美观

    npm install antd --save
    

    分别复制以下代码到 index.js ,index.css

    index.js

    import React from "react";
    import ReactDOM from "react-dom";
    import { Button, Divider, Input, Row, Col } from "antd";
    import "antd/dist/antd.css"; // or 'antd/dist/antd.less'
    import "./index.css";
    class List extends React.Component {
      render() {
        return (
          <div className="list">
            <Row className="list-item">
              <Col span={16}>col</Col>
              <Col span={4}><Button>修改</Button></Col>
              <Col span={4}><Button>删除</Button></Col>
            </Row>
          </div>
        );
      }
    }
    class Add extends React.Component {
      render() {
        return (
          <div className="add">
          <Input
            placeholder="请输入需要添加的事项"
            allowClear
          />
          <Button type="primary">添加</Button>
        </div>
        );
      }
    }
    
    class TodoList extends React.Component {
      constructor(props) {
        super(props);
        this.state = {};
      }
      render() {
        return (
          <div className="todolist">
            <Divider>TodoList</Divider>
            <Add />
            <List />
          </div>
        );
      }
    }
    
    // ========================================
    
    ReactDOM.render(<TodoList />, document.getElementById("root"));
    
    

    index.css

    *{
        margin: 0;
        padding: 0;
    }
    html,body{
        height: 100vh;
        overflow: hidden;
    }
    .todolist{
         400px;
        height: 630px;
        margin: 100px auto;
        border: 2px solid #000;
        padding: 20px;
    }
    .list{
        height: 430px;
        overflow-y: scroll;
    }
    .list-item{
        margin-top: 20px;
    }
    .add{
        display: flex;
    }
    .performance{
        display: flex;
        justify-content: space-between;
    }
    .finish{
        text-decoration:line-through;
        text-line-through-color:red
    }
    

    启动项目,这时我们已经可以看到 TodoList 大致的样子了

    npm start
    

    如图所示

    编写添加功能

    这个小案例,我采用的是所有数据都交由父组件处理,然后分发给子组件,所以我们先在父组件的 state 里面声明一个 text 和 list,text 用于存储输入框的值,list 用于存储添加的列表。

      constructor(props) {
        super(props);
        this.state = {
          list: [],
          text: "",
        };
      }
    

    编写输入框的 change 事件,利用一起传入的text赋值给输入框的value属性实现数据的双向绑定并通过添加事件获取text来修改list,其中我们用时间戳来当做添加数据的id,完整代码如下

    TodoList

    class TodoList extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          list: [],
          text: "",
        };
      }
      // 绑定输入框的值
      handleChange(e) {
        e.persist();
        this.setState({
          text: e.target.value,
        });
      }
      //添加
      handleAdd() {
        if (!this.state.text) {
          alert("输入框不能为空");
          return;
        }
        const Itme = { text: this.state.text, id: Date.now()};
        this.setState({
          list: [Itme, ...this.state.list],
          text: "",
        });
      }
      render() {
        return (
          <div className="todolist">
            <Divider>TodoList</Divider>
            <Add
              change={(e) => this.handleChange(e)}
              text={this.state.text}
              addClick={() => this.handleAdd()}
            />
            <List list={this.state.list}/>
          </div>
        );
      }
    }
    

    Add

    class Add extends React.Component {
      render() {
        return (
          <div className="add">
            <Input
              placeholder="请输入需要添加的事项"
              onChange={(e) => this.props.change(e)}
              allowClear
              value={this.props.text}
            />
            <Button type="primary" onClick={() => this.props.addClick()}>添加</Button>
          </div>
        );
      }
    }
    
    

    通过遍历父组件传过来的list生成当前列表

    List

    class List extends React.Component {
      render() {
        const list = this.props.list
        return (
          <div className="list">
          {list.map((item) => (
            <Row className="list-item" key={item.id}>
              <Col span={16} >{item.text}</Col>
              <Col span={4}>
                <Button type="primary">修改</Button>
              </Col>
              <Col span={4}>
                <Button type="primary" danger>删除</Button>
              </Col>
            </Row>
          ))}
          </div>
        );
      }
    }
    

    添加修改功能

    在父组件的 state 里面声明一个 AddOrUpdate 变量来存储当前是处于添加状态还是修改状态及需要修改项的id,在默认的清空下是处于添加状态,可以通过修改按钮更改为修改状态,当修改完成后还原成添加状态

    TodoList

    class TodoList extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          list: [],
          text: "",
          AddOrUpdate: { isAdd: true },
        };
      }
      // 绑定输入框的值
      handleChange(e) {
        e.persist();
        this.setState({
          text: e.target.value,
        });
      }
      //添加 | 修改
      handleAdd() {
        if (!this.state.text) {
          alert("输入框不能为空");
          return;
        }
        if (this.state.AddOrUpdate.isAdd) {
          const Itme = { text: this.state.text, id: Date.now(), isFinish: false };
          this.setState({
            list: [Itme, ...this.state.list],
            text: "",
          });
        } else {
          let { id } = this.state.AddOrUpdate;
          let newlist = this.state.list;
          newlist.map((item) => item.id === id && (item.text = this.state.text));
          this.setState({
            list: [...newlist],
            AddOrUpdate: { isAdd: true },
            text: "",
          });
        }
      }
      //修改
      handleUpdate(item) {
        this.setState({
          AddOrUpdate: { isAdd: false, id: item.id },
          text: item.text,
        });
      }
      render() {
        return (
          <div className="todolist">
            <Divider>TodoList</Divider>
            <Add
              change={(e) => this.handleChange(e)}
              text={this.state.text}
              addClick={() => this.handleAdd()}
              AddOrUpdate={this.state.AddOrUpdate}
            />
            <List
              list={this.state.list}
              update={(item) => this.handleUpdate(item)}
            />
          </div>
        );
      }
    }
    

    Add

    class Add extends React.Component {
      render() {
        return (
          <div className="add">
            <Input
              placeholder="请输入需要添加的事项"
              onChange={(e) => this.props.change(e)}
              allowClear
              value={this.props.text}
            />
            <Button type="primary" onClick={() => this.props.addClick()}>
              {this.props.AddOrUpdate.isAdd ? "添加" : "确定修改"}
            </Button>
          </div>
        );
      }
    }
    

    List

    class List extends React.Component {
      render() {
        const list = this.props.list;
        return (
          <div className="list">
            {list.map((item) => (
              <Row className="list-item" key={item.id}>
                <Col span={16}>{item.text}</Col>
                <Col span={4}>
                  <Button type="primary" onClick={() => this.props.update(item)}>
                    修改
                  </Button>
                </Col>
                <Col span={4}>
                  <Button
                    type="primary"
                    danger
                  >
                    删除
                  </Button>
                </Col>
              </Row>
            ))}
          </div>
        );
      }
    }
    

    添加删除功能

    这里我是通过filter来筛除点击的列表项实现删除功能的

      //删除
      handleDelete(item) {
        this.setState({
          list: this.state.list.filter((i) => i.id !== item.id),
        });
      }
    

    接下来我们来实现最后一个功能了,也就是查询功能

    我的思路是这样子的,给每条数据增加一个自定义状态(完成和未完成),默认都是未完成,通过点击当前项来修改当前数据的状态,
    设置三个按钮(全部,未完成,已完成),然后在父组件设置一个变量来存储这三个状态,通过分别点击这三个按钮来状态,然后把这个状态传递给列表组件(List组件),通过filter实现数据的筛选,因为我们所有的子组件的不包含state,所以我们可以优化一下都写成函数式组件

    完整代码如下

    import React from "react";
    import ReactDOM from "react-dom";
    import { Button, Divider, Input, Row, Col } from "antd";
    import "antd/dist/antd.css"; // or 'antd/dist/antd.less'
    import "./index.css";
    
    function List(props) {
      let list = props.list;
      if(props.condition === 'finish'){
        list = list.filter(item=>item.isFinish)
      }
      if(props.condition === 'unfinished'){
        list = list.filter(item=>!item.isFinish)
      }
      return (
        <div className="list">
          {list.map((item) => (
            <Row className="list-item" key={item.id}>
              <Col span={16} onClick={() => props.isFinish(item)} className={item.isFinish ? 'finish': null}>
                {item.text}
              </Col>
              <Col span={4}>
                <Button type="primary" onClick={() => props.update(item)}>
                  修改
                </Button>
              </Col>
              <Col span={4}>
                <Button
                  onClick={() => props.deleteClick(item)}
                  type="primary"
                  danger
                >
                  删除
                </Button>
              </Col>
            </Row>
          ))}
        </div>
      );
    }
    function Add(props) {
      return (
        <div className="add">
          <Input
            placeholder="请输入需要添加的事项"
            allowClear
            onChange={(e) => props.change(e)}
            value={props.text}
          />
          <Button type="primary" onClick={() => props.addClick()}>
            {props.AddOrUpdate.isAdd ? "添加" : "确定修改"}
          </Button>
        </div>
      );
    }
    function Performance(props) {
      return (
        <div className="performance">
          {
            props.status.map(item=>(
            <Button type="primary" onClick={()=>props.statusClick(item.state)} key={item.state}>{item.text}</Button>
            ))
          }
        </div>
      );
    }
    class TodoList extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          list: [],
          text: "",
          AddOrUpdate: { isAdd: true },
          status:[
            {
              text:'全部',
              state:'All'
            },
            {
              text:'已完成',
              state:'finish'
            },
            {
              text:'未完成',
              state:'unfinished'
            }
          ],
          condition:'All'
        };
      }
      handleAdd() {
        if (!this.state.text) {
          alert("输入框不能为空");
          return;
        }
        if (this.state.AddOrUpdate.isAdd) {
          const Itme = { text: this.state.text, id: Date.now(),isFinish:false};
          this.setState({
            list: [Itme, ...this.state.list],
            text: "",
          });
        } else {
          let { id } = this.state.AddOrUpdate;
          let newlist = this.state.list;
          newlist.map((item) => item.id === id && (item.text = this.state.text));
          this.setState({
            list: [...newlist],
            AddOrUpdate: { isAdd: true },
            text: "",
          });
        }
      }
      handleDelete(item) {
        this.setState({
          list: this.state.list.filter((i) => i.id !== item.id),
        });
      }
      handleChange(e) {
        e.persist();
        this.setState({
          text: e.target.value,
        });
      }
      handleUpdate(item) {
        this.setState({
          AddOrUpdate: { isAdd: false, id: item.id },
          text: item.text,
        });
      }
      handleIsFinish(data) {
        let newlist = this.state.list;
        newlist.map((item) => item.id === data.id && (item.isFinish = !item.isFinish));
        this.setState({
          list: [...newlist],
        });
      }
      handleStatus(state){
        this.setState({
          condition:state
        })
      }
      render() {
        return (
          <div className="todolist">
            <Divider>TodoList</Divider>
            <Add
              addClick={() => this.handleAdd()}
              text={this.state.text}
              change={(e) => this.handleChange(e)}
              AddOrUpdate={this.state.AddOrUpdate}
            />
            <List
              list={this.state.list}
              deleteClick={(item) => this.handleDelete(item)}
              update={(item) => this.handleUpdate(item)}
              isFinish={(item) => this.handleIsFinish(item)}
              condition={this.state.condition}
            />
            <Performance status={this.state.status} statusClick={(state)=>this.handleStatus(state)}/>
          </div>
        );
      }
    }
    
    // ========================================
    
    ReactDOM.render(<TodoList />, document.getElementById("root"));
    
    

    总结

    react --TodoList 学习之旅到此结束了,希望我的学习经验能让大家有所收获,如有更好的实现方法可以在评论区留言哦!!!

    线上demo

  • 相关阅读:
    Git批量删除的方法
    第五课 森さんは 七時に 起きます
    第一课 李さんは  中国人です
    如何设置上传文件控件 input type="file" 的 默认值
    如何用程序提交一个上传文件的请求
    MVC Beta 做的网站实践总结(上)
    泛型单一模式
    提高web站点性能的最佳实践
    扩展GridView实现的一个自定义无刷新分页,排序,支持多种数据源的控件TwfGridView
    [导入]将字符串中连续的空格转换为一个空格
  • 原文地址:https://www.cnblogs.com/r-mp/p/13563708.html
Copyright © 2011-2022 走看看