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悬停提示、状态色条和移动端适配,构建专业级用户体验 该项目完整展现了现代前端开发的三大核心优势: 组件复用性数据驱动性工程高效性

最后效果展示:

相关推荐
辻戋3 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保3 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun4 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp4 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.5 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl7 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫8 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友8 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理10 小时前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻10 小时前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js