🧩 React 组件化进阶:像乐高大师一样搭建你的应用世界!
"当你在拼接 DOM 碎片时,我在组装预制的功能模块------这就是组件化思维的分水岭!" 🚀
🔍 重新认识 Vite:你的前端工程"智能工厂"
(图示:现代化工厂流水线示意图)
传统开发 vs Vite 工程化:
- 手工小作坊:直接写 HTML/CSS/JS → 适用于微型页面
- Vite 智能工厂 :
- 🏗️ 自动构建流水线(代码编译/打包)
- 🔥 实时热更新引擎(修改即生效)
- 📦 模块化装载系统(依赖管理)
- ⚡ 闪电开发服务器(端口 5173 的奥秘)
为何需要特定端口?
就像工厂需要专用输电网(端口)供电,Vite 服务器实时处理:
- 模块热替换(HMR)
- CSS 预处理器编译
- 文件路径重定向
- API 请求代理
bash
# 启动你的工厂流水线
npm run dev
# 输出:
VITE v5.2.0 ready in 220 ms
➜ Local: http://localhost:5173/
➜ Network: use --host to expose

🧱 组件:前端世界的乐高积木
何为组件: 在 React 里,组件是构建用户界面的基础单位。它把 UI 划分成多个独立、可复用的模块,每个模块都能独立维护。组件的核心优势是复用性、可维护性以及可测试性。
组件的表现显示是什么:
- 类组件(Class Components)
类组件属于较早的组件定义方式,它借助 ES6 的 class 来继承React.Component
,并且要定义render()
方法。下面是类组件的示例:
javascript
import React, { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
- 函数组件(Function Components)
函数组件是更为简洁的组件定义方式,它其实就是 JavaScript 函数。函数组件接收 props 作为参数,然后返回 JSX 元素。下面是函数组件的示例:
javascript
import React from 'react';
const Welcome = (props) => {
return <h1>Hello, {props.name}</h1>;
};
- 无状态组件(Stateless Components)
无状态组件是只负责渲染 UI,不管理自身状态的组件。类组件和函数组件都可以成为无状态组件。下面是无状态函数组件的示例:
javascript
const Button = ({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
);
- 有状态组件(Stateful Components)
有状态组件能够管理和更新自身状态。在过去,只有类组件可以是有状态组件,不过自从 React 16.8 引入 Hooks 之后,函数组件也能使用useState
Hook 来管理状态了。下面是使用 Hooks 的有状态函数组件示例:
javascript
import React, { useState } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
};
- 高阶组件(Higher-Order Components, HOC)
高阶组件是一种特殊的组件,它接收一个组件作为参数,然后返回一个新的组件。高阶组件主要用于代码复用和状态逻辑共享。下面是高阶组件的示例:
javascript
const withLogging = (WrappedComponent) => {
return class extends React.Component {
componentDidMount() {
console.log(`Component ${WrappedComponent.name} mounted`);
}
render() {
return <WrappedComponent {...this.props} />;
}
};
};
- 函数式组件与 Hooks
React 16.8 引入的 Hooks 让函数组件可以使用状态和生命周期方法等类组件的特性。常见的 Hooks 有useState
、useEffect
、useContext
等。下面是使用多个 Hooks 的函数组件示例:
javascript
import React, { useState, useEffect } from 'react';
const UserProfile = ({ userId }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
setLoading(true);
fetch(`/api/users/${userId}`)
.then((res) => res.json())
.then((data) => {
setUser(data);
setLoading(false);
});
}, [userId]);
return loading ? (
<p>Loading...</p>
) : (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
};
- 纯组件(Pure Components)
纯组件会自动浅比较 props 和 state,只有当它们发生变化时才会重新渲染。类组件可以通过继承React.PureComponent
来成为纯组件。函数组件则可以使用React.memo
来实现相同的功能。下面是纯函数组件的示例:
javascript
const PureButton = React.memo(({ label, onClick }) => (
<button onClick={onClick}>{label}</button>
));
组件类型 | 定义方式 | 状态管理 | 生命周期支持 | 性能优化 | 适用场景 | 代码复杂度 | 示例语法 |
---|---|---|---|---|---|---|---|
类组件 | 继承 React.Component |
有(this.state ) |
完整 | 手动优化或PureComponent |
复杂状态/生命周期依赖 | 高 | class Counter extends Component { state={count:0}; render(){...} } |
函数组件(无Hooks) | 普通JS函数 | 无 | 无 | 无 | 纯展示组件 | 低 | const Button = (props) => <button>{props.label}</button> |
函数组件(有Hooks) | 函数 + Hooks | 有(useState ) |
useEffect 模拟 |
React.memo +useCallback |
大多数场景 | 中 | const Counter=()=>{const [c,setC]=useState(0);return...} |
纯组件 | 继承 React.PureComponent |
有 | 完整 | 自动浅比较 | 性能敏感组件 | 中 | class PureCounter extends PureComponent {...} |
高阶组件(HOC) | 函数接收组件返回新组件 | 取决于实现 | 取决于实现 | 需手动处理 | 代码复用/渲染劫持 | 高 | const withAuth = (Comp) => (props) => {...} |
Hooks组件 | 函数 + 组合Hooks | 灵活 | 灵活 | React.memo +自定义Hooks |
复杂逻辑复用 | 中高 | const Profile=()=>{const {user}=useAuth();...} |
组件的选择建议
- 优先选用函数组件和 Hooks,因为它们的代码更简洁,并且能更好地复用状态逻辑。
- 只有在确实需要使用复杂的生命周期方法时,才考虑使用类组件。
- 运用高阶组件和
React.memo
来优化性能和复用逻辑。
(图示:乐高积木拼装成复杂结构)
组件的本质 = HTML + CSS + JS 的功能单元:如果把组件比作积木,那传统的标签就如同沙子一般
jsx
// 传统标签:原子级操作
<button>Click</button>
<input type="text" />
// React 组件:功能级封装
<PaymentForm />
<UserProfileCard />
<DataVisualizationChart />
TodoList 组件化拆解示例:
组件开发黄金法则:
- 单一职责原则 :每个组件只解决一个问题(如
TodoItem
只负责单条待办) - 高内聚低耦合:组件内部紧密协作,对外接口简单明确
- 可复用优先:像乐高积木一样设计可重复使用的组件
📂 项目目录:组件化工程的车间布局
markdown
my-app/
├── src/
│ ├── components/ # 组件仓库
│ │ ├── Header/
│ │ │ ├── Header.jsx
│ │ │ └── Header.css
│ │ ├── TodoList/
│ │ │ ├── TodoList.jsx
│ │ │ ├── TodoItem.jsx
│ │ │ └── AddForm.jsx
│ ├── App.jsx # 总装流水线
│ └── index.css # 全局样式库
src文件内的代码,将会是我们未来主要使用修改的 模块化导入示例:
jsx
// App.jsx
import Header from './components/Header/Header';
import TodoList from './components/TodoList/TodoList';
function App() {
return (
<div className="app">
<Header />
<TodoList />
</div>
);
}
⚙️ 组件化开发实战:TodoList 深度解构

这段代码实现了一个基础的待办事项列表应用,由三个核心组件构成:
App
、TodoList
和 TodoForm
,Todos
,我们来看看它们是如何联系起来的:
组件关系概览
-
App
组件(根组件)- 作为整个应用的入口,渲染
TodoList
组件。 - 无状态,仅负责组件组合。
- 作为整个应用的入口,渲染
-
TodoList
组件(状态管理核心)- 管理待办事项的状态(
todos
)和标题(title
)。 - 提供添加待办的方法(
handleAdd
)。 - 渲染
TodoForm
(表单输入)和Todos
(列表展示)。
- 管理待办事项的状态(
-
TodoForm
组件(表单输入)- 负责处理用户输入和表单提交。
- 通过回调函数(
onAdd
)将输入数据传递给父组件(TodoList
)。
-
Todos
组件(列表展示)- 接收父组件传递的
todos
数据并渲染列表。
- 接收父组件传递的
完整代码注解
jsx
//App.jsx
import { useState } from 'react'
import './App.css'
import TodoList from './components/TodoList'
function App() {
return (
<>
<TodoList/>
{/* 自定义的组件插入点 */}
</>
)
}
export default App
jsx
//TodoList.jsx
//内置的hook 函数
import { useState } from 'react'
import '../Todo.css'
import TodoForm from './TodoForm'
import Todos from './Todos'
//为什么函数是一个组件?
function TodoList(){
//数据驱动的界面
//静态页面?
//DOM编程 数组->map->join('')->innerHTML底层API 编程
//缺点:低效、面向API
//面向业务 懂业务
//数据 -> 变化 -> 数据状态 -> 自动刷新页面 -> **数据**驱动页面
//返回数组,第一项是数据变量,第二项是一个函数 执行,并传入新的todos的值
// 页面会自动刷新
//挂载点 tbody
//{todos.map}
//setTodos DOM及动态更新
//响应式界面开发
//hi 数据状态 sethi 修改数据状态的方法
//es6 解构
const[hi,setHi]=useState('haha')
// const hi=useState('haha')[0];
// const setHi=useState('haha')[1];
const [title,setTitle]=useState('Todo list')
const [todos,setTodos]=useState([
{
id:1,
text:'吃饭',
completed:false//是否完成s
}
])
const handleAdd =(text)=>{
setTodos([
...todos,
// 把原来的保留
{
id:todos.length+1,
text,
completed:false
}
])
}
// setTimeout(()=>{
// setTodos([
// ...todos,
// {
// id:2,
// text:'睡觉',
// completed:false//是否完成
// }
// ])
// setTitle('字节')
// setHi('加油')
// },3000)
return(
<div className="container">
<h1 className="title">{title}{hi}</h1>
{/* 表单 */}
<TodoForm onAdd={handleAdd}/>
{/* 列表 */}
<Todos todos={todos}/>
{/* {
//当下这个位置
//数据为王,界面是被驱动的
//数据驱动
//数据绑定 data binding
//发生改变 自动改变
todos.map(todo=>(
<li>{todo.text}</li>
))
} */}
</div>
)
}
export default TodoList;//将组件导出,向外输出
jsx
//TodoForm.jsx
import { useState } from "react";
function TodoForm(props) {
const onAdd=props.onAdd
const[text,setText]=useState('打豆豆')
const handleSubmit=(e)=>{
//阻止默认的行为
//由js控制
e.preventDefault();
//console.log(text);
onAdd(text)
//如何修改todos? 打报告
}
const handleChange=(e)=>{
setText(e.target.value)
}
return (
<form action="http://www.baidu.com" onSubmit={handleSubmit}>
<input
type="text"
placeholder="请输入代办事项"
// 占位置,一个输入框一定要写placeholder 增强语义化
value={text}
onChange={handleChange}
/>
<button type='submit'>添加</button>
</form>
)
}
export default TodoForm;
jsx
//Todos.jsx
//列表的渲染
function Todos(props){
console.log(props,'/////')
//父组件传过来的数据呢?传参
const todos=props.todos
return(
<ul>
{
todos.map(todo=>(
<li key={todo.id}> {todo.text} </li>
))
}
</ul>
)
}
export default Todos;
1. <TodoForm onAdd={handleAdd} />
的作用
这行代码是在TodoList
组件中渲染TodoForm
组件,并通过onAdd
属性传递了一个回调函数handleAdd
。这个模式称为反向数据流(Child-to-Parent Communication):
- 父组件(TodoList) 定义了状态
todos
和修改状态的函数handleAdd
- 子组件(TodoForm) 通过
props.onAdd
接收这个函数,并在用户提交表单时调用它 - 数据流向是单向的:从父组件到子组件,再通过回调函数返回
2. TodoForm 组件的实现
这个组件负责渲染一个输入表单,并将用户输入传递给父组件:
javascript
function TodoForm(props) {
const onAdd = props.onAdd; // 从父组件接收回调函数
const [text, setText] = useState('打豆豆'); // 本地状态:输入框内容
const handleSubmit = (e) => {
e.preventDefault(); // 阻止表单默认提交行为
onAdd(text); // 调用父组件的回调函数,传递输入内容
};
const handleChange = (e) => {
setText(e.target.value); // 更新本地状态
};
return (
<form action="http://www.baidu.com" onSubmit={handleSubmit}>
<input
type="text"
placeholder="请输入代办事项"
value={text}
onChange={handleChange}
/>
<button type='submit'>添加</button>
</form>
);
}
关键细节:
-
受控组件 :输入框的值由 React 状态
text
控制,实现双向数据绑定 -
事件处理:
handleChange
:实时更新输入框内容到本地状态handleSubmit
:阻止表单默认提交,调用父组件的onAdd
函数
-
数据流:
- 用户输入内容 ->
handleChange
更新text
状态 - 用户点击提交 ->
handleSubmit
触发onAdd(text)
- 父组件的
handleAdd
函数被调用,更新todos
列表
- 用户输入内容 ->
3. Todos 组件的实现
这个组件负责渲染待办事项列表,接收父组件传递的todos
数组:
javascript
function Todos(props) {
const todos = props.todos; // 从父组件接收todos数组
return (
<ul>
{todos.map(todo => (
<li key={todo.id}> {todo.text} </li>
))}
</ul>
);
}
关键细节:
- props 接收数据 :通过
props.todos
获取父组件传递的待办事项列表 - 列表渲染 :使用
.map()
方法遍历数组,生成<li>
元素 - key 属性 :每个列表项必须有唯一的
key
,这里使用todo.id
确保 React 能正确识别每个元素
数据流总结
这个待办事项应用的数据流遵循单向数据流原则:
-
TodoList 组件 持有状态
todos
和修改状态的函数handleAdd
-
TodoList 将
handleAdd
传递给TodoForm 作为onAdd
属性 -
TodoList 将
todos
数组传递给Todos 组件作为todos
属性 -
TodoForm 在用户提交时调用
onAdd(text)
,触发父组件的状态更新 -
Todos 组件接收到更新后的
todos
数组,自动重新渲染列表
这种模式使得数据流向清晰可控,是 React 应用的核心设计模式。
🧠 组件化思维:从沙粒到摩天大楼的进化
(图示:从散沙到结构化建筑的演变过程)
前端开发的认知升级:
原始时代:HTML标签(5分,沙粒)、CSS样式(3分,颜料)
农耕时代:DOM操作(2分,手工烧砖)、jQuery(4分,简单工具)
工业时代:组件化(8分,预制构件)、工程化(7分,流水线生产)

组件化核心优势:
- 高效复用 :一次开发,随处调用(如
<Button>
组件) - 团队协作:多人并行开发不同组件
- 维护简易:故障组件可单独替换
- 业务聚焦:开发者专注功能逻辑而非 DOM 操作
组件调试大法:专业前端开发人员必备
在chrome中下载插件chromewebstore.google.com/detail/reac...
然后通过终端给你的端口,打开你创建的react项目,右键,检查
在这里就可以观察该项目所有的组件,便于维护

💡 React 开发心法:数据驱动视图的艺术
传统 DOM 操作 vs React 数据驱动:
js
// 传统方式:手动操作DOM(易出错)
document.getElementById('list').innerHTML += `
<li>${newTodoText}</li>
`;
// React方式:更新数据,自动渲染(优雅!)
setTodos(prev => [...prev, newTodo]);
数据状态管理三原则:
- 单一数据源:状态提升到最近公共父组件
- 不可变数据 :永远通过
setState
更新状态 - 向下流动:数据通过 props 单向传递
jsx
// 状态提升示例
function Parent() {
const [data, setData] = useState([]); // 状态在此管理
return (
<ChildA data={data} />
<ChildB onDataUpdate={setData} />
);
}
🚀 成为组件化大师的终极秘诀
-
拆分思维训练:
- 拿到设计稿先画组件树
- 按功能边界切割组件
- 组件文件保持300行内
-
组件设计模式掌握:
markdown- 容器组件 vs 展示组件 - 高阶组件(HOC) - Render Props - 复合组件(Compound Components)
-
工具链精通:
bash# 组件文档工具 npm install -D storybook # 组件测试工具 npm install -D @testing-library/react
-
性能优化意识:
React.memo
缓存组件- 避免 props 不必要变更
- 惰性加载组件(
lazy + Suspense
)
"不会拆分组件的React开发者,就像用挖掘机搭积木------力量有余,精度不足!" 🏗️💥