likes
comments
collection
share

如何使用react创建一个实战小项目

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

背景

最近学了React组件化的思路,便有了做一个小项目的想法

如何使用react创建一个实战小项目

看到桌面上的待办事项,便有了想法,做一个todolist

设计

对于react来说,分模块的开发React将应用程序分解为独立且可复用的组件。这种方法带来了诸多好处,包括但不限于:

模块化开发的好处

  1. 代码可读性和可维护性

    • 组件化使代码更加模块化,每个组件负责单一职责,这使得代码更容易理解和维护。
    • 当功能发生变化或需要修改时,定位和更新相关的组件变得更加简单。
  2. 测试性

    • 单个组件易于单元测试,可以独立验证组件的功能和行为,确保其按预期工作。
  3. 性能优化

    • 通过使用虚拟DOM和只重新渲染发生更改的组件,React能够提高应用程序的性能。
    • 分模块打包可以减少首屏加载时间,因为用户只加载他们当前需要的代码。
  4. 灵活性和扩展性

    • 模块化的组件可以轻松地添加、移除或替换,提高了系统的灵活性和适应性。
    • 新的功能或设计可以更容易地集成到现有的应用程序结构中。
  5. 易于学习和上手

    • 对于新加入的开发人员,模块化组件使得系统更易于理解和上手,因为他们可以逐个组件地学习整个应用。

React中的模块化开发策略不仅提升了开发效率,还改善了代码质量,增强了应用程序的性能和可维护性。

好处这么多,那应该如何去设计好呢?

如何使用react创建一个实战小项目

如何使用react创建一个实战小项目

todoform组件去处理表单提交

你可以输入input框中在todoform组件handleChange 函数通过 event.target.value 获取用户的输入值,并使用 this.setState 来更新组件的 inputText 状态,从而使组件的状态与用户的输入保持同步。这个状态更新会触发组件的重新渲染,因此用户在界面上看到的输入框中的值会实时更新。

再创建应该todoitem组件去把需要的每一个需要做的todo去编写需要的功能

todoitem组件:

  • 组件结构:TodoItem 组件被设计为一个 <li> 元素,包含了待办事项的文本和一些交互按钮。

  • 数据传递:通过 props 从父组件接收必需的属性。这些属性包括:

    • todo:一个表示待办事项的对象,其中包含 text(事项文本)和 completed(完成状态)属性。
    • index:一个索引值,用于唯一标识每一个待办事项。
    • toggleTodo:一个函数,用于切换当前待办事项的完成状态。
    • deleteTodo:一个函数,用于从列表中删除当前待办事项。
    • editTodo:一个函数,用于保存当前待办事项的编辑内容。
  • 状态管理:TodoItem 组件使用 React 的 state 来管理本地状态。在构造函数中,初始化了两个状态属性:

    • isEditing:一个布尔值,指示当前待办事项是否正在被编辑。初始化为 false
    • editText:一个字符串,保存正在编辑的文本内容。初始化为 todo.text
  • 事件处理器:为了处理用户的交互,定义了几个事件处理器:

    • handleEditChange:处理编辑输入框的值变化事件,更新 editText 状态。
    • handleEditSave:当用户点击“保留”按钮时,调用 editTodo 函数,将编辑后的文本保存,并更新 isEditing 状态为 false
  • 渲染逻辑:根据 isEditing 状态的不同,render 方法渲染不同的界面:

    • 当 isEditing 为 false:显示待办事项的文本,并提供 “编辑”、“删除” 按钮。文本被点击时调用 toggleTodo 函数。
    • 当 isEditing 为 true:显示一个输入框和一个 “保留” 按钮。输入框的值由 editText 状态控制,且通过 onChange 事件调用 handleEditChange。点击“保留”按钮时调用 handleEditSave

todolist组件:

  1. 组件结构:整个 Todolist 组件由一个无序列表 ul 组成,每个列表项 li 代表一个待办事项。列表项使用 todo-item CSS 类进行样式设置,并且通过添加或移除 todo-item_completed 类来表示事项的完成状态。
  2. 数据传递:Todolist 组件接收一个 todos 属性,这是一个待办事项的数组。每个待办事项对象包含 text 和 completed 属性。text 属性显示在列表项的 <span> 元素中,completed 属性用于应用样式。
  3. 方法传递toggleTodo 和 deleteTodo 方法分别通过props传递给 Todoitem 组件,以允许用户在列表项上进行交互操作。toggleTodo 方法用于切换单个事项的完成状态,deleteTodo 方法用于移除指定的事项。
  4. 遍历渲染:在 render 方法中,使用 map 函数遍历 todos 数组,为每个 todo 对象创建一个 Todoitem 组件实例。每个实例使用唯一的 key 属性来确保 React 能够高效地更新和渲染。
  5. 交互性:每个 Todoitem 组件实例都渲染为一个 <li> 元素,它包含 <span> 来显示文本,以及三个 <button> 按钮。用户可以点击 <span> 文本区来切换完成状态(通过调用 toggleTodo)、点击 删除 按钮来调用 deleteTodo,或者点击 编辑 按钮来设置 isEditing 状态为 true,从而进入编辑模式。
  6. 编辑模式:当 Todoitem 组件处于编辑模式(isEditing 为 true)时,它将显示一个输入框 <input>,允许用户编辑待办事项的文本。输入框的值由 editText 状态控制,并通过 handleEditChange 事件处理器更新。当用户点击 保留 按钮时,handleEditSave 事件处理器将被调用,以保存编辑后的文本。
  7. 状态管理:在 constructor 中初始化组件的状态(isEditing 和 editText),并提供事件处理器(handleEditChange 和 handleEditSave)来管理编辑时的交互。

App组件

在App组件内去添加addTodo toggleTodo deleteTodo editTodo 事件处理函数,去添加管理todo的函数,把整体页面布局切出来

源代码

App.jsx

import React, { Component } from "react"
import Todolist from './components/todolist'
import Todoform from "./components/todoform"
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('todo'))||[];

    this.state = {
      todos:savedtodos      
      ,
    }

  }

  componentDidUpdate(){
    instance.setItem('todo',JSON.stringify(this.state.todos))
  }
  addTodo = (text) => {
    this.setState({

      todos : [
        ...this.state.todos,
        {
          text,
          completed:false,
        }
      ]
  })
  }
  toggleTodo = (index) => {
    const newTodos = [...this.state.todos]
    newTodos[index].completed = !newTodos[index].completed
    this.setState({
      todos: newTodos
    })
  }
  deleteTodo = (index) => {
    const newTodos = [...this.state.todos];
    newTodos.splice(index,1);
    this.setState({
      todos:newTodos
    })
  }

  editTodo = (index,text) => {
    const newTodos = [...this.state.todos];//重新开辟一个新数组,重新去拿到相关的值,避免和之前的数据纠缠
    newTodos[index].text = text;
    this.setState({
      todos:newTodos
    })
  }
  



  render(){
    const {todos} = this.state;

    
    return(
          <div className ='todo-app'>
            <h1 className="todo-app__title">Todo List</h1>
            <Todoform addTodo={this.addTodo}></Todoform>
            <Todolist todos={todos}
                      toggleTodo={this.toggleTodo}
                      deleteTodo={this.deleteTodo}
                      editTodo={this.editTodo}></Todolist>

          </div>
    )
  }
}



export default App


需要注意点:

1、 自定义React组件的类名和函数名应以大写字母开头。 在JSX中,React根据首字母是否大写来区分自定义组件和HTML原生元素。 以大写字母开头的名称被认为是React组件,如 < TodoForm />。以小写字母开头的名称被认为是HTML原生元素,如< div >。所以在这里面不能去创建< todoform >这种React不会识别成自定义组件

2、使用localStorage进行持久化存储,localStorage 是一个用于在浏览器端存储数据的对象。这些数据存储在用户的浏览器中,并且即使在浏览器关闭后,数据仍然保留着,除非用户手动清除浏览器缓存。这种数据存储方式非常适合需要持久化存储的场景,例如:记住用户的登录状态、保存用户的偏好设置等。

3、componentDidUpdate(){ instance.setItem('todo',JSON.stringify(this.state.todos)) }在 React 中,componentDidUpdate 生命周期方法允许在组件更新后执行一些操作。在你的 App 组件中,componentDidUpdate 方法被用来在 todos 状态更新后,将最新的 todos 数据持久化到 localStorage

4、 Todoform组件传递addTodo方法:在渲染Todoform时,通过props将addTodo方法传递给它,以便子组件能够调用该方法添加新任务。 Todolist组件传递todos数据:将todos数组通过props传递给Todolist组件,以便在子组件中显示任务列表。

5、 修正class属性:在JSX中,使用className而不是class来定义CSS类名。

6、数据管理:Props是一种父组件向子组件传递数据的方式。它们是只读的,意味着子组件不能修改由父组件传递过来的props。

todoform.jsx

import React, { 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() {
    return (
      <form className="todo-form" onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.inputText}
          className="todo-form__input"
          onChange={this.handleChange}
        />
        <button type="submit" className="todo-form__button">
          提交
        </button>
      </form>
    );
  }
}

export default TodoForm;


需要注意点:

1、this.props.addTodo(this.state.inputText); this.setState({ inputText: '' });在你提交完表单数据后把输入框中的值添加完以后需要把输入框的值清空inputText: ''

todolist.jsx

import { Component } from "react";
import Todoitem from './todoitem.jsx'
import './todolist.css'

class todolist extends Component{
    
    constructor(props){
        super(props)


    }

    render(){
        const { todos,
                 toggleTodo,//todoitem组件中需要用到toggleTodo方法
                 deleteTodo,
                 editTodo,
         } = this.props
        return(
            <ul className="todo-list">
                {todos.map((todo,index) =>(//遍历todos数组 回调函数中todo为数组中的元素 index为数组中的索引
                    <Todoitem 
                    key={index} 
                    todo={todo} 
                    index={index} 
                    toggleTodo={toggleTodo} 
                    deleteTodo={deleteTodo}
                    editTodo={editTodo}></Todoitem>
                ))}
            </ul>

        )
    }
}

export default todolist

todoitem.jsx


import { Component } from 'react'
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 = () => {
        this.props.editTodo(this.props.index, this.state.editText)
        this.setState({
            isEditing: false
        })
    }
    
    render() {
        const { 
            todo,
            index,
            toggleTodo,
            deleteTodo,
        } =  this.props
        const { isEditing, editText } = this.state
        const { text, completed, } = todo
        // JS 运行区域
        return (
            <li className={`todo-item ${completed?'todo-item_completed':''}`} >
                {isEditing?(
                  <div>
                    <input 
                     type="text"
                     value={editText} 
                     onChange={this.handleEditChange} 
                     className="todo-item__Save"/>
                     <button className='todo-item__edit-input' onClick={this.handleEditSave}>保留</button>
                  </div>
                ):<div>
                    
                <span className='todo-item__text' onClick={() => toggleTodo(index)}>
                    {text}
                </span>
                
                <button className='todo-item__delete-btn'
                 onClick={() => deleteTodo(index)}>删除</button>
                 <button className='todo-item__edit-btn'
                 onClick={() => this.setState({isEditing: true})}>编辑</button>
                
            
            
                 </div>
                  }


            </li>
        )
    }
}

export default TodoItem

storage.js

class Storage {
    // static instance;
    static getInstance() {
        // JS 动态  static 属性
        // JS 没有类,都是对象
        if (!Storage.instance) {
            Storage.instance = new Storage();
        }
        return Storage.instance;
    }

    getItem(key) {
        return localStorage.getItem(key);
    }

    setItem(key, value) {
        localStorage.setItem(key, value);
    }
}

// new Storage();

export default Storage

这里使用localstorage 单例模式去持久化存储数据,这样在浏览器中会缓存数据,就算把页面关闭也不会导致数据丢失。单例模式是一种创建对象的模式,确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。单例模式在许多库和框架中都有使用,特别是在需要维护全局状态或需要在整个应用程序中共享资源的情况下,这里用单例模式能保证只会创建一个Storage对象。

展示效果

如何使用react创建一个实战小项目

在这个todolist里你可以提交你需要做的事情,编辑你需要做的事情,如果你做完了一件事情,你还可以点击事情让这个事情变成灰色,表示你已经做完,删除你不想做的事情。

我这边加了一些css样式,我的样式也不好看就不拿出来了,如果有需要可以私信我。

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