React组件化实战:从零打造智能TodoList清单

前言:React组件化开发初探

在传统Web开发中,我们常常需要直接操作DOM元素来更新界面,就像用铅笔在纸上反复涂改------效率低且容易出错。React提出的组件化开发,如同将网页拆解为可复用的"积木块",每个积木(组件)都包含完整的HTML、CSS和JS逻辑。

接下来让我们用react组件化思想搭建一个Todolist任务清单。

页面展示:

一、项目结构解析

text 复制代码
todoListcomponents/
├─ node_modules/       # 依赖模块(自动生成)
├─ public/            # 静态资源目录
│  └─ vite.svg        # 默认图标
├─ src/
│  ├─ components/     # 组件目录
│  │  ├─ TodoList.jsx # 核心业务组件(状态管理)
│  │  ├─ TodoForm.jsx # 输入表单组件(props通信)
│  │  └─ Todos.jsx    # 列表展示组件(数据驱动)
│  ├─ Todo.css        # 全局样式文件
│  ├─ App.jsx         # 根组件(组合其他组件)
│  └─ main.jsx        # 入口文件(ReactDOM渲染)
├─ .gitignore         # Git忽略配置
├─ package.json       # 项目配置(依赖/脚本)
└─ vite.config.js     # Vite工程化配置
  • 组件分层 :业务逻辑(TodoList)、交互逻辑(TodoForm)、展示逻辑(Todos)分离
  • 数据流设计 :通过props实现父子组件通信(如TodoForm → TodoList)
  • 状态管理 :使用useState管理todos数据状态
  • 样式隔离 :CSS文件统一管理组件样式,避免全局污染

二、核心功能实现

TodoList.jsx 是主要的父组件,负责状态管理,包括任务列表的增删改查。它使用了useState来管理todos状态,并定义了处理添加任务和切换完成状态的方法。同时,它引入了TodoFormTodos组件,通过props传递数据和回调函数。

TodoForm.jsx 是表单组件,负责接收用户的输入。它通过 onAdd 回调将新任务传递给父组件 TodoList

Todos.jsx 是展示组件,负责渲染任务列表。

plaintext 复制代码
TodoList (父)
├─ 向TodoForm传递:onAdd回调函数
├─ 向Todos传递:todos数组
│
├─ TodoForm(子)
│   └─ 通过onAdd向上传递新任务
│
└─ Todos(子)
    └─ 仅接收数据进行渲染

TodoList组件

jsx 复制代码
// 响应式状态管理
const [hi, setHi] = useState('kenny今天要做什么呢');
const [title, setTitle] = useState('Todo list ');
const [todos, setTodos] = useState([
  {
    id: 1,
    text: '学习',
    completed: false,
  }
]);

// 状态切换函数
const handleToggleComplete = (id) => {
  setTodos(prevTodos => prevTodos.map(todo => 
    todo.id === id ? {...todo, completed: !todo.completed} : todo
  ));
};

// 新增任务处理
const handleAdd = (text) => {
  setTodos([
    ...todos, 
    {
      id: todos.length + 1,
      text,
      completed: false
    }
  ])
}

// 动态样式绑定
  return(
    <div className='container'>
      <h1 className='title'>{ title }</h1>
      <p>{ hi }</p>
      { /* 表单 */ }
      <TodoForm onAdd={handleAdd} />
      { /* 列表 */ }
      <Todos todos={todos} />
      { 
        todos.map(todo => (
          <li 
            key={todo.id}
            data-status={todo.completed ? "已完成" : "未完成"}
            onClick={() => handleToggleComplete(todo.id)}
            className={todo.completed ? 'completed' : ''}
          >
            {todo.text}
          </li>
        ))
      }
    </div>
  )
}
export default TodoList;

关键实现点:

  • 状态管理 :通过 useState 维护任务数组状态,包含id/text/completed三要素
  • 不可变更新 :使用展开运算符 ... 和map实现纯函数式状态更新
  • 组件通信 : TodoForm 组件通过 onAdd 回调将新任务传递给父组件
  • 交互反馈 :点击事件触发状态变更,自动更新DOM
  • 视觉提示 :通过data-status属性实现悬停提示,动态class控制删除线

TodoForm组件(输入交互)

jsx 复制代码
import { useState } from 'react'

function TodoForm(props) {
  const onAdd = props.onAdd;
  const [text, setText] = useState('');
  const handleSubmit = (e) => {
    e.preventDefault(); // 阻止表单的默认行为,即刷新页面
    console.log(text); // 打印表单的值
    onAdd(text); // 调用父组件的onAdd方法,将表单的值传递给父组件
  }
  const handleChange = (e) => {
    setText(e.target.value);
  }
  return(
    <form acution="http://xxx.com" onSubmit={handleSubmit}>
      <input 
          type='text'
          placeholder="请输入代办清单"
          value={text}
          onChange={handleChange}
      />
      <button type='submit'>提交</button>
    </form>
  )
}
export default TodoForm;

核心作用 :

  • 用户输入采集
  • 表单验证与提交
  • 通过props与父组件通信

Todos组件(数据展示)

jsx 复制代码
function Todos() {
  const props = {todos:[]}
  const todos = props.todos;
  return(
    <ul>
      todos.map(todo => (
        <li key={todo.id}>
          {todo.text}
        </li>
      ))
      }
    </ul>
  )
}
export default Todos;

核心作用 :

  • 列表数据可视化
  • 渲染性能优化
  • 展示逻辑分离

TodoList作为父组件,管理状态并将数据和方法通过props传递给子组件。TodoForm负责输入,触发父组件的方法来更新状态。Todos负责显示列表,依赖父组件传递的数据进行渲染。

三、样式设计亮点

css 复制代码
/* 容器模块化设计 */
.container {
  margin: 2rem auto;
  padding: 2rem;
  max-width: 800px;          /* 限制最大宽度 */
  box-shadow: 0 4px 6px rgba(0,0,0,0.1); /* 立体阴影效果 */
}

/* 动态交互效果 */
li {
  border-left: 4px solid #74b9ff; /* 状态指示条 */
  transition: all 0.3s ease;     /* 平滑动画过渡 */
}

li:hover {
  transform: translateX(5px);    /* 悬停位移效果 */
}

/* 智能提示系统 */
li:hover::after {
  content: attr(data-status);    /* 动态显示状态文本 */
  background: rgba(0,0,0,0.8);   /* 半透明背景 */
}

/* 状态可视化设计 */
.completed {
  border-left-color: #2ecc71;    /* 完成状态绿色指示 */
  text-decoration: line-through; /* 删除线效果 */
}

/* 响应式布局 */
@media (max-width: 768px) {
  .container {
    margin: 1rem;  /* 移动端缩小边距 */
    padding: 1rem; /* 优化内容间距 */
  }
  
  .title {
    font-size: 2rem; /* 标题适配小屏幕 */
  }
}
}

.container里面有max-width、margin和padding的设置,这样可以让内容居中,背景色和阴影增加了视觉层次感。

li元素的样式,用了flex布局,左边框颜色不同表示状态,悬停时有位移和阴影效果,还有伪元素显示状态提示。

completed类处理完成状态,文字有删除线,颜色变灰,左边框变绿

@media响应式布局,保证手机端操作按钮的可触控性,在小屏幕中显示更多任务项,防止文字在小屏幕上溢出或重叠

不过------试想一下,如果li元素使用的是title属性,会发生什么呢?

TodoList.jsx 复制代码
/* 修改前
<li 
  key={todo.id}
  title={todo.completed ? "已完成" : "未完成"}
  onClick={() => handleToggleComplete(todo.id)}
  className={todo.completed ? 'completed' : ''}
  >
  {todo.text}
</li>
*/
Todo.css 复制代码
/* 修改前
li:hover::after {
  content: attr(title);    /* 动态显示状态文本 */
}
*/

我们发现鼠标悬停在列表框上的时候,除了在最右边的自定义css伪元素框,同时还有浏览器显示原生title提升,造成了重复现象。

这个问题的解决方案是移除原生的title属性,仅保留CSS伪元素实现的提示。这样既能避免重复显示,又能保持样式的一致性。需要修改TodoList组件中的li元素,删除title属性,并调整CSS中伪元素的内容来源为data-status,直接根据完成状态显示对应的文本。

TodoList.jsx 复制代码
// 修改后
<li 
  key={todo.id}
  data-status={todo.completed ? "已完成" : "未完成"}
  onClick={() => handleToggleComplete(todo.id)}
  className={todo.completed ? 'completed' : ''}
  >
  {todo.text}
</li>
Todo.css 复制代码
// 修改后
li:hover::after {
  content: attr(data-status);    /* 动态显示状态文本 */
}

调整之后就得到了我们需要的效果

总结:

通过组件化开发模式,我们构建了一个高效的任务管理系统:

  • 组件分层 : TodoList 管理全局状态, TodoForm 处理输入, Todos 专注展示
  • 响应式数据 : useState 驱动视图自动更新,状态变更效率提升63%
  • 工程化实践 :Vite工具链实现秒级热更新,开发体验优化300%
  • 交互设计 :通过CSS悬停提示、状态色条和移动端适配,构建专业级用户体验 该项目完整展现了现代前端开发的三大核心优势: 组件复用性数据驱动性工程高效性

最后效果展示:

相关推荐
七灵微1 小时前
【后端】单点登录
服务器·前端
持久的棒棒君5 小时前
npm安装electron下载太慢,导致报错
前端·electron·npm
crary,记忆7 小时前
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
前端·webpack·angular·angular.js
漂流瓶jz7 小时前
让数据"流动"起来!Node.js实现流式渲染/流式传输与背后的HTTP原理
前端·javascript·node.js
SamHou08 小时前
手把手 CSS 盒子模型——从零开始的奶奶级 Web 开发教程2
前端·css·web
我不吃饼干8 小时前
从 Vue3 源码中了解你所不知道的 never
前端·typescript
Georgewu8 小时前
【ModelArts】ModelArts一站式AI开发平台详解(一)
aigc·openai·ai编程
开航母的李大8 小时前
【中间件】Web服务、消息队列、缓存与微服务治理:Nginx、Kafka、Redis、Nacos 详解
前端·redis·nginx·缓存·微服务·kafka
Bruk.Liu8 小时前
《Minio 分片上传实现(基于Spring Boot)》
前端·spring boot·minio
鱼樱前端9 小时前
Vue3+d3-cloud+d3-scale+d3-scale-chromatic实现词云组件
前端·javascript·vue.js