likes
comments
collection
share

用react组件化的思想实现一个todoList

作者站长头像
站长
· 阅读数 26

前言

react中最引以为傲的特性之一:组件化-->将应用分解成一系列可复用的组件。 每个组件都是独立的、可测试的,并且可以拥有自己的状态和生命周期。 它给许许多多的大型项目开发带来的便利,使编程的思想来到另一个维度,目的是为了项目中的各个模块便于管理,减少管理成本,以及增强可读性。

今天我们就以组件的思想来完成一个小demo---todoList,它的主要实现效果如下:

用react组件化的思想实现一个todoList

动态效果如下:

主要实现的功能有:

  1. 添加待办事项todoitem
  2. 显示代办事项
  3. 编辑待办事项
  4. 删除待办事项

组件设计

由上述效果展示以及功能的需求,我们大概可以分为三个小组件,将其插入在根组件App中。 ①todoForm表单组件---->输入框 ②todoList展示列表组件 ---->List展示框 ③todoitem将列表中的各项item分离成一个组件 ---->List中的个体 当然不能忘了根组件App

细节设计

1.todoForm ①构造函数接受参数传值 ②handleChange函数,将表单输入的值绑定给变量,实现双向绑定。 ③handleSubmit函数,在确认表单提交时,将列表的数据改变,并将表单内容清空 ④将处理函数事件绑定表单上

todoForm组件源码如下:

import { Component } from "react";
import './TodoForm.css'
class TodoForm extends Component{
    constructor(props){
        super(props)
        this.state = {
            inputText:''
        }
    }
    handleChange = (event)=>{
        this.setState({
            inputText:event.target.value
        })
    }

    handleSubmit = (e)=>{
        e.preventDefault()
        if(this.state.inputText.trim()){
            this.props.addTodo(this.state.inputText)
            this.setState({
                inputText:''
            })
        }
    }
    render(){
        let inputtext = this.state.inputText
        return(
            <div className="form1">
            <form action="" className="todo-Form" onSubmit={this.handleSubmit}>
                <input 
                type="text"
                value = {inputtext}
                className="todo-form__input"
                onChange={this.handleChange}
                />
                <button type="submit"
                className="todo-form__button"
                >
                    确定
                </button>
            </form>
            </div>
        )
    }
}
export default TodoForm

2.todoList ①将列表数据作为数组,用map函数列出各个循环项todoitem,用ul>li结构

todoList组件源码如下:

import { Component } from "react";
import TodoItem from "./TodoItem";
import './TodoList.css'
// 容器组件
class TodoList extends Component{
    // constructor(props){
    //     super(props)
    // }
    render(){
        const {
            todos,
            deleteTodo,
            toggleTodo,
            editTodo,

        } = this.props
        return(
            <ul className="todo-list">
                {todos.map((todo,index)=>(
                    <TodoItem 
                        key={index}
                        index={index}
                        todo={todo}
                        deleteTodo={deleteTodo}
                        toggleTodo={toggleTodo}
                        editTodo={editTodo}
                    />
                ))
                }
            </ul>
        )
    }
}
export default TodoList

3.todoitem ①handleEditChange函数,处理编辑时的状态改变,当编辑的值改变时绑定给变量,实现双向绑定。 ②handleEditSave函数,当编辑完保存时,修改数据,并将编辑框的状态设置为false(为了在false状态下将编辑框隐藏) ③将函数挂载到相应标签上

todoitem组件源码如下:

import { Component } from "react";
import TodoList from "./TodoList";
import './TodoItem.css'
class TodoItem extends Component{
    constructor(props){
        super(props)
        this.state = {
            isEditing: false,
            editText:this.props.todo.text
        }
    }
    handleEditChange=(event)=>{
        this.setState({editText:event.target.value})
    }
    handleEditSave= (event)=>{
        this.props.editTodo(this.props.index,this.state.editText)
        this.setState({isEditing:false})
    }

    render(){
        const { todo,
            toggleTodo,
            index,
            deleteTodo
         } = this.props
        const {isEditing,editText} = this.state 
        const { text,completed} = todo
        return(
            <li className={`todo-item ${completed?'todo-item_completed':''}`}>
                {isEditing ?(
                    <div>
                        <input type="text" 
                        value={editText}
                        onChange={this.handleEditChange}
                        className="todo-item__edit-input"
                        />
                        <button className="todo-item__save-btn" onClick={this.handleEditSave}>Save</button>
                    </div>
                ):<div>
                    <span className="todo-item__text" onClick={()=>toggleTodo(index)}>
                {text}
                </span>
                
                </div>}
                
                <button
                    onClick={()=> this.setState({isEditing: true})}
                    className="todo-item__edit-btn"
                >Edit</button>
                <button
                    className="todo-item__delete"
                    onClick={()=>deleteTodo(index)}
                >Delete</button>
                
            </li>
            
        )
    }
}
export default TodoItem

4.App根组件 ①在App中我们封装了一个叫做Storage的类,目的是实现localStorage的单例模式,类只实例化一次。 ②将列表数据和localStorage中的数据双向绑定 ③在componentDidUpdate生命周期函数中启用本地数据存储列表数据 ④addTodo实现添加一项todoitem ⑤deleteTodo实现列表通过下标的方式从列表数组中删除todoitem ⑥toggleTodo点击代办事项,将其转为完成状态 ⑦editTodo编辑代办事项,接受index和newText两个参数

App根组件源码如下:

import TodoForm from './TodoForm'
import TodoList from './TodoList'
import './App.css'
import Storage from './utils/Storage'

const instance = Storage.getInstance()
class App extends Component{
  constructor(props){
    super(props)
    const savedTodos = JSON.parse(instance.getItem('todos')) || []
    this.state = {
      todos:savedTodos
    }
  }
  componentDidUpdate(){
    instance.setItem('todos',JSON.stringify(this.state.todos))
  }
  addTodo = (text)=>{
    this.setState({
      todos:[
        ...this.state.todos,
        {
          text,
          completed:false
        }
      ]
    })

  }

  deleteTodo = (index)=>{
    const newTodos = [...this.state.todos]
    newTodos.splice(index,1)
    this.setState({
      todos:newTodos
    })
  }

  toggleTodo = (index)=>{
    const newTodos = [...this.state.todos]
    newTodos[index].completed =!newTodos[index].completed
    this.setState({
      todos:newTodos
    })
  }

  editTodo = (index,newText) =>{
    const newTodos = [...this.state.todos]
    newTodos[index].text = newText
    this.setState({
      todos:newTodos
    })
  }
  // 组件必须要有一个界面,返回的jsx
  render(){
    const { todos } = this.state
    return (
      <div className="todo-app">
        <h1 className="todo-app__title">Todo List</h1>
        <div className="main1">
        <TodoForm addTodo={this.addTodo}/>
        <TodoList
          todos = {todos}
          toggleTodo={this.toggleTodo}
          deleteTodo={this.deleteTodo}
          editTodo={this.editTodo}  // 编辑todo项的函数,在TodoList中使用
        /></div>
      </div>
    )
  }
}

export default App

这样我们就完成了这个小demo的实战开发,由于css样式再展示,可能文章过于冗长,样式小伙伴们可以自行编辑。

转载自:https://juejin.cn/post/7388091090321653786
评论
请登录