前端实践-使用React实现待办事项 | 豆包MarsCode AI刷题

36 阅读6分钟

React Todo List 学习笔记

在深入学习 React 的过程中,我通过实现一个 Todo List 应用来加深对 React 核心概念的理解。这个应用虽然简单,但它涉及到了 React 的许多基础和高级特性,包括组件化、状态管理、事件处理和条件渲染等。

基础语法

JSX 是 React 的一个语法扩展,它允许我们在 JavaScript 中写类似 HTML 的代码。JSX 在编译后会变成 React 的 createElement() 函数调用,这是 createElement() 函数的语法糖。

  1. Map 遍历与 Key
    在 React 中,当我们需要遍历数组并为每个元素渲染一个组件时,我们必须为每个元素提供一个唯一的 key 属性。这是 React 识别哪些元素改变了、添加了或被移除的推荐方式。
  2. Fragment 的使用
    Fragment 允许你将多个子元素包裹起来,而不需要向 DOM 添加额外节点,这在多个组件返回时非常有用。
  3. 驼峰命名法
    React 中的属性命名遵循驼峰命名法,这是 JavaScript 中常用的命名约定,使得代码更加一致和易于阅读。
  4. useState 钩子与状态管理
    React 的 useState 钩子允许我们在函数组件中添加状态。这是 React Hooks 的一个核心特性,它使得函数组件能够处理状态和生命周期方法。
  5. 展开运算符与状态更新
    在更新对象状态时,使用展开运算符可以确保我们不会意外地修改原始对象,同时能够覆盖对象的属性。
  6. 组件通信
    React 中的组件通信主要通过 props 来实现。父组件可以将数据和回调函数传递给子组件,子组件通过 props 接收这些数据和回调函数。

一、组件化和 JSX

React 的组件化思想是将 UI 拆分成独立、可复用的组件。在我的 Todo List 应用中,整个应用被视为一个大型组件 App,而每个待办事项可以被视为一个更小的组件。JSX 作为 React 中的语法糖,让我能够以一种更接近 HTML 的方式来描述 UI 结构,同时保持 JavaScript 的灵活性。

二、状态管理

状态(state)是 React 组件中非常重要的一部分,它代表了 UI 的状态。在我的应用中,状态被用来存储待办事项列表、输入框的内容以及编辑状态。useState 钩子是 React 提供的一种在函数组件中添加状态的方式,它让我能够轻松地在组件中管理状态。

在我的代码中,我使用了三个状态变量:todos 用于存储待办事项列表,input 用于存储输入框的内容,editId 用于存储当前正在编辑的待办事项的 ID。这些状态的初始化如下:

jsx
const [todos, setTodos] = useState([]);
const [input, setInput] = useState('');
const [editId, setEditId] = useState(null);

三、事件处理

事件处理是用户与应用交互的关键。在我的 Todo List 应用中,我处理了表单提交、任务删除、编辑和保存等事件。React 中的事件处理与原生 DOM 事件类似,但 React 要求我们传递事件处理函数,而不是字符串。这种方式使得事件处理更加直观和易于管理。

在我的代码中,handleSubmit 函数处理表单提交事件,handleDelete 函数处理删除事件,handleEdithandleSave 函数处理编辑和保存事件:

jsx
const handleSubmit = (e) => {
  e.preventDefault();
  if (input.trim() !== '') {
    setTodos([...todos, { id: Date.now(), text: input }]);
    setInput('');
  }
};

const handleDelete = (id) => {
  setTodos(todos.filter(todo => todo.id !== id));
};

const handleEdit = (todo) => {
  setEditId(todo.id);
  setEditText(todo.text);
};

const handleSave = (id) => {
  setTodos(todos.map(todo =>
    todo.id === id ? { ...todo, text: editText } : todo
  ));
  setEditId(null);
};

四、条件渲染

条件渲染是根据应用的状态来决定是否渲染某些组件或元素。在我的应用中,当一个待办事项处于编辑状态时,我渲染了一个输入框和一个保存按钮,而不是显示待办事项的文本。这种根据状态动态渲染 UI 的能力是 React 强大灵活性的体现。

在我的代码中,条件渲染体现在对每个待办事项的处理上:

jsx
{todos.map(todo => (
  <li key={todo.id}>
    {editId === todo.id ? (
      <>
        <input
          type="text"
          value={editText}
          onChange={(e) => setEditText(e.target.value)}
        />
        <button onClick={() => handleSave(todo.id)}>保存</button>
      </>
    ) : (
      <>
        <span>{todo.text}</span>
        <button onClick={() => handleEdit(todo)}>编辑</button>
        <button onClick={() => handleDelete(todo.id)}>删除</button>
      </>
    )}
  </li>
))}

五、不可变性和数组操作

在处理状态更新时,React 推荐我们使用不可变的方式更新状态,特别是在处理数组时。在我的应用中,当删除一个待办事项时,我使用了 filter 方法来创建一个新的数组,而不是直接修改原始数组。这种方式有助于避免意外的副作用,并使得状态变化更加可预测。

六、组件通信

组件通信是 React 应用中另一个重要的概念。在我的 Todo List 应用中,我使用了 props 来传递数据和回调函数。例如,每个待办事项组件接收到一个 handleEdithandleDelete 函数作为 props,这些函数在父组件中定义,并负责更新状态。

七、高阶组件和 Hook

虽然我的应用没有直接使用高阶组件(HOC)和自定义 Hook,但这些是 React 提供的用于复用组件逻辑的强大工具。HOC 允许我们通过组合来重用组件逻辑,而自定义 Hook 允许我们在不同的组件间复用状态逻辑。

八、性能优化

虽然在我的 Todo List 应用中没有直接涉及到性能优化,但 React 提供了多种性能优化手段,如 shouldComponentUpdateReact.PureComponentReact.memo。这些工具可以帮助我们减少不必要的渲染,提高应用的性能。

九、React 的哲学与最佳实践

React 的设计哲学强调了声明式编程和组件的可复用性。声明式编程让我们更关注“做什么”而不是“怎么做”,这使得代码更加简洁和易于维护。组件化则让我们能够将复杂的 UI 拆分成更小、更易于管理的部分。每个组件都封装了自己的状态和行为,这有助于我们保持代码的清晰和模块化。

  1. 组件的单一职责
    每个组件应该只负责 UI 的一小部分,并且只包含与其功能相关的逻辑。这有助于我们保持组件的简洁和可维护性。
  2. props 和状态的使用
    props 是父组件传递给子组件的数据,而状态是组件内部管理的数据。正确地使用 props 和状态可以帮助我们构建可预测和可维护的组件。
  3. 高阶组件和 Hook
    React 提供了高阶组件(HOC)和 Hook 来复用组件逻辑。HOC 是基于函数的抽象,而 Hook 是在函数组件中使用状态和其他 React 特性的方式。
  4. 性能优化
    React 提供了多种性能优化手段,如 shouldComponentUpdate、React.PureComponent 和 React.memo。这些工具可以帮助我们减少不必要的渲染,提高应用的性能。

总的来说,React 是一个强大且灵活的库,它通过组件化和声明式编程提供了构建用户界面的新方式。通过深入理解 React 的核心概念和最佳实践,我们可以构建出高效、可维护和可扩展的前端应用。

通过实现这个 Todo List 应用,我不仅加深了对 React 基础概念的理解,还学习了如何将这些概念应用到实际的项目中。这个应用虽然简单,但它涵盖了 React 的许多核心特性,为我进一步学习更复杂的 React 应用打下了坚实的基础。

屏幕截图 2024-11-23 095710.png

屏幕截图 2024-11-23 095824.png