用react组件化的思想实现一个todoList
前言
react中最引以为傲的特性之一:组件化-->将应用分解成一系列可复用的组件。 每个组件都是独立的、可测试的,并且可以拥有自己的状态和生命周期。 它给许许多多的大型项目开发带来的便利,使编程的思想来到另一个维度,目的是为了项目中的各个模块便于管理,减少管理成本,以及增强可读性。
今天我们就以组件的思想来完成一个小demo---todoList,它的主要实现效果如下:
动态效果如下:
主要实现的功能有:
- 添加待办事项todoitem
- 显示代办事项
- 编辑待办事项
- 删除待办事项
组件设计
由上述效果展示以及功能的需求,我们大概可以分为三个小组件,将其插入在根组件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