使用React实现一个简单的日程表组件 | 青训营

71 阅读2分钟

一、写作缘由

最近学习了React基础,想找个小项目复习巩固一下,就写了一个简单的日程表组件。虽然只是一个小项目,但是开发中间出现了很多次错误,简单记录一下。

二、组件展示

image.png

三、功能描述

  • 右上角可以添加新日程,放在正在执行类别中
  • 日程表下有三种类型的日程:正在执行已完成已删除
  • 点击状态切换:正在执行-->已完成-->已删除

四、组件组合

在React中几乎不使用继承,而是使用组合。在本例中,正在执行已完成已删除三个类别的日程只是标题和前面的图标不一样,其他基本一样。在面向对象设计方法中,这简直是一个完美的继承模型,但是在React中却是使用组合实现的。在Schedule组件中将具有特殊性的东西提取出来,让ExecutingScheduleFinishedScheduleDeletedSchedule来提供,从而通过组合实现了继承的效果。

五、组件源码

ScheduleList.js

import React, { Component } from 'react'
import './Schedule.css'

function ScheduleSample(props){
    let schedules = props.schedules;
    return (
        <div>
            <h3>{props.title}</h3>
            <ul className={props.icon}>
                {
                    schedules.map((schedule)=>{
                        return <li key={schedule.id} onClick={(e)=>{props.handleClick(schedule)}} status={schedule.status}><i></i>{schedule.content}</li>
                    })
                }
            </ul>
        </div>
    )
}

const Schedule = React.memo(ScheduleSample);

function FinishedSchedule(props){
    return (
        <Schedule title="已完成的日程" {...props} icon='finished'></Schedule>
    )
}

function DeletedSchedule(props){
    return (
        <Schedule title="已删除的日程" {...props} icon='deleted'></Schedule>
    )
}

function ExecutingSchedule(props){
    return (
        <Schedule title="正在执行的日程" {...props} icon='executing'></Schedule>
    )
}



export default class ScheduleList extends Component {
    constructor(props){
        super(props);
        this.state = {
            scheduleText: "",
            scheduleCount: 9,
            scheduleList: [
                {id: 1, content: "看电视", status: "executing"},
                {id:2, content: "做作业", status: "executing"},
                {id:3, content: "打篮球", status: "executing"},
                {id: 4, content: "看电视", status: "deleted"},
                {id:5, content: "做作业", status: "deleted"},
                {id:6, content: "打篮球", status: "deleted"},
                {id: 7, content: "看电视", status: "finished"},
                {id:8, content: "做作业", status: "finished"},
                {id:9, content: "打篮球", status: "finished"}
            ]
        };
    }

    handleInputChange = (e)=>{
        let val = e.target.value;
        this.setState({scheduleText: val});
    }

    addSchedule = ()=>{
        if(this.state.scheduleText){
            this.setState((prevState)=>({
                scheduleCount: (prevState.scheduleCount + 1),
                scheduleList: prevState.scheduleList.concat({id: (prevState.scheduleCount+1), content: prevState.scheduleText, status: "executing"}),
                scheduleText: "",
            }));
        }
    }

    statusChange = (s)=>{
        const key = s.id;
        const status = s.status;
        this.setState((prevState)=>{
            let scheduleList = prevState.scheduleList;
            let scheduleObj = scheduleList.find(((schedule)=>schedule.id === key));
            if(status === 'executing'){
                scheduleObj.status = 'finished';
            }else if(status === 'finished'){
                scheduleObj.status = 'deleted';
            }else{

            }
            return {scheduleList}
        });
    }

    render() {
        return (
            <div className='schedule-list'>
                <div className='schedule-list-header'>
                    <h2>日程列表</h2>
                    <div>
                        <input className='input-add' type='text' value={this.state.scheduleText} onChange={this.handleInputChange}/>
                        <button className='button-add' onClick={this.addSchedule}>添加日程</button>
                    </div>
                    
                </div>

                <div className='schedule-list-content'>
                    <ExecutingSchedule schedules={this.state.scheduleList.filter((schedule)=>schedule.status === 'executing')} handleClick={this.statusChange}></ExecutingSchedule>
                    <FinishedSchedule schedules={this.state.scheduleList.filter((schedule)=>schedule.status === 'finished')} handleClick={this.statusChange}></FinishedSchedule>
                    <DeletedSchedule schedules={this.state.scheduleList.filter((schedule)=>schedule.status === 'deleted')} handleClick={this.statusChange}></DeletedSchedule>
                </div>
            </div>
        );
    }
}

ScheduleList.css

ul{
    list-style-type: none;
}

.deleted{
    list-style-image: url('deleted.png');
}

.finished{
    list-style-image: url('finished.png');
}

.executing{
    list-style-image: url('executing.png');
}

li:hover{
    background-color: aliceblue;
}

.schedule-list{
    box-sizing: border-box;
    width: 40%;
    background-color: antiquewhite;
}

.schedule-list-header{
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-left: 20px;
    margin-right: 20px;

}

.schedule-list-header>h2{
    order: 1
}

.schedule-list-header>div{
    order: 2
}

.button-add{
    margin-left: 1px;
}

六、重要知识点记录

  1. 列表数据渲染使用map
(
        <div>
            <h3>{props.title}</h3>
            <ul className={props.icon}>
                {
                    schedules.map((schedule)=>{
                        return <li key={schedule.id} onClick={(e)=>{props.handleClick(schedule)}} status={schedule.status}><i></i>{schedule.content}</li>
                    })
                }
            </ul>
        </div>
    )

2.对象列表中给定条件的对象的查找


this.state = {
            scheduleText: "",
            scheduleCount: 9,
            scheduleList: [
                {id: 1, content: "看电视", status: "executing"},
                {id:2, content: "做作业", status: "executing"},
                {id:3, content: "打篮球", status: "executing"},
                {id: 4, content: "看电视", status: "deleted"},
                {id:5, content: "做作业", status: "deleted"},
                {id:6, content: "打篮球", status: "deleted"},
                {id: 7, content: "看电视", status: "finished"},
                {id:8, content: "做作业", status: "finished"},
                {id:9, content: "打篮球", status: "finished"}
            ]
        };

let scheduleObj = this.state.scheduleList.find(((schedule)=>schedule.id === key));

let schedules = this.state.scheduleList.filter((schedule)=>schedule.status === 'deleted'));

七、问题记录

  • 事件处理函数中的this指向问题
  • 数据传递过程中的undefined问题