摘要
本文档系统介绍了React基础语法与项目工程化实践,涵盖JSX核心规则、Hooks状态管理、组件通信机制及企业级项目结构设计,并对比了React与Vue的核心差异,适合前端开发者快速掌握React开发范式。

1. React的基础语法
1.1. React 核心概念
React 本质:
- 用组件构建 UI
- 数据驱动视图(state 变化 → UI 自动更新)
- 单向数据流(父 → 子)
2. JSX 语法(React 的核心)
2.1. 什么是 JSX
const element = <h1>Hello World</h1>;
👉 本质:
React.createElement(...)
2.2. JSX 基本规则
2.2.1. ✔ 必须有一个根节点
<>
<div></div>
<span></span>
</>
2.2.2. ✔ JS 表达式写法
const name = "Tom";
<h1>Hello {name}</h1>
2.2.3. ✔ 条件渲染
{isLogin ? <Home /> : <Login />}
2.2.4. ✔ 列表渲染(非常重要)
list.map(item => <li key={item.id}>{item.name}</li>)
👉 key 必须唯一!
2.3. 组件(核心思想)
2.3.1. 函数组件(主流)
function User() {
return <div>User</div>;
}
2.3.2. 类组件(了解即可)
class User extends React.Component {
render() {
return <div>User</div>;
}
}
2.3.3. 组件嵌套
function App() {
return <User />;
}
2.4. Props(组件参数)
类似你后端的DTO入参
2.4.1. 基本用法
function User(props) {
return <div>{props.name}</div>;
}
<User name="Tom" />
2.4.2. 构写法(推荐)
function User({ name }) {
return <div>{name}</div>;
}
2.4.2.1. ✔ 函数组件必须大写
function MyButton() {} ✅
function myButton() {} ❌(会被当成 HTML 标签)
2.4.2.2. ✔ 函数必须返回一个"根节点"
return (
<div>
<button>按钮</button>
</div>
);
或:
<>
<button />
</>
2.4.3. ✔ 函数可以接收参数(props)
function MyButton({ text }) {
return <button>{text}</button>;
}
使用:
<MyButton text="删除" />
2.5. State(组件状态)
👉 类似"页面内变量",变化会触发 UI 更新
2.5.1. useState(核心)
import { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
2.5.2. 特点
-
更新是异步
-
不要直接改变量:
count = count + 1 ❌
setCount(count + 1) ✅
2.6. 事件处理
2.6.1. 基本事件
<button onClick={handleClick}>点击</button>
2.6.2. 传参
<button onClick={() => handleClick(id)}>点击</button>
2.6.3. 表单处理(重点)
<input value={value} onChange={e => setValue(e.target.value)} />
👉 叫:受控组件
2.7. 生命周期/Hooks(重点)
2.7.1. useEffect(最重要)
useEffect(() => {
console.log("组件加载");
return () => {
console.log("组件卸载");
};
}, []);
2.7.2. 常见场景
|----------|--------------------|
| 场景 | 用法 |
| 页面加载请求接口 | useEffect |
| 监听变量变化 | useEffect([dep]) |
| 清理定时器 | return |
2.7.3. 常见 Hooks
|-------------|--------|
| Hook | 作用 |
| useState | 状态 |
| useEffect | 副作用 |
| useRef | DOM/缓存 |
| useMemo | 性能优化 |
| useCallback | 函数缓存 |
2.8. 条件渲染 & 列表渲染(高频)
2.8.1. 条件
{isShow && <div>显示</div>}
2.8.2. 列表
users.map(user => (
<div key={user.id}>{user.name}</div>
))
2.9. 组件通信(非常重要)
2.9.1. 父 → 子通信
<Child name="Tom" />
2.9.2. 子 → 父 通信
function Child({ onClick }) {
return <button onClick={onClick}>点我</button>;
}
2.9.3. 跨组件(进阶)
- Context
- 状态管理
2.10. 表单 & 受控组件
const [value, setValue] = useState("");
<input
value={value}
onChange={e => setValue(e.target.value)}
/>
👉 React 推荐:全部受控
2.11. 样式写法
2.11.1. 行内样式
<div style={{ color: "red" }}></div>
2.11.2. className
<div className="box"></div>
2.12. 路由(页面跳转)
👉 常用:React Router
<Route path="/home" element={<Home />} />
2.13. 状态管理(中大型项目)
2.13.1. 常见方案
- Context(轻量)
- Redux(经典)
- Pinia(Vue生态,你之前学过)
2.13.2. API请求
useEffect(() => {
fetch("/api/user")
.then(res => res.json())
.then(data => setData(data));
}, []);
2.14. ES的导入模块
export default function MyApp() {
return (
<div>
<h1>欢迎来到我的应用</h1>
<MyButton />
</div>
);
}
2.14.1. export default ------ ES 模块导出
这是 JavaScript 模块语法(ES Module)
export default function MyApp() {}
含义:
把这个函数"默认导出",供其他文件使用
2.14.2. ✔ 使用方式:
import MyApp from "./MyApp";
👉 注意:
- 不需要
{}(默认导出) - 可以随便改名字(但一般不改)
2.14.3. function MyApp() ------ 函数组件
function MyApp() {}
👉 在 React 中:
返回 JSX 的函数 = 组件
👉 所以:
MyApp 是一个"组件"
2.14.4. return (...) ------ 返回 JSX
return (
<div>
<h1>欢迎来到我的应用</h1>
<MyButton />
</div>
);
👉 JSX(HTML + JS 语法)
JSX 做了什么?
<div>...</div>
本质是:
React.createElement(...)
2.14.5. 4️⃣ <MyButton /> ------ 使用组件
<MyButton />
👉 表示:
渲染另一个组件
👉 前提是你必须有:
function MyButton() {
return <button>按钮</button>;
}
3. 标准 React 项目结构(推荐)
src/
├── main.jsx # 入口文件(挂载 React)
├── App.jsx # 根组件
├── assets/ # 静态资源(图片、icon、字体)
├── styles/ # 全局样式
├── components/ # 公共组件(复用)
│ ├── Table/
│ ├── Modal/
│ └── Button/
├── pages/ # 页面(路由级别)
│ ├── Manager/
│ │ ├── index.jsx
│ │ ├── service.js
│ │ └── components/
│ │ └── EditModal.jsx
│ └── Login/
├── services/ # 全局 API 请求封装
│ ├── request.js
│ └── systemField.js
├── hooks/ # 自定义 Hook(逻辑复用)
│ ├── useTable.js
│ └── useRequest.js
├── utils/ # 工具类
│ ├── format.js
│ └── auth.js
├── router/ # 路由配置
│ └── index.jsx
├── store/ # 状态管理(可选)
│ └── userStore.js
├── constants/ # 常量定义
│ └── index.js
└── config/ # 配置(环境变量等)
└── index.js
3.1. 每一层"职责"解释(非常重要)
你可以类比后端三层架构👇
3.1.1. 1️⃣ pages(= Controller + 页面)
👉 页面入口(路由级)
职责:
- 页面结构
- 调用接口
- 组织组件
3.1.2. 2️⃣ components(= 公共组件库)
👉 可复用 UI 组件
特点:
- 不依赖具体业务
- 高复用
例子:
- Table
- Form
- Modal
3.1.3. 3️⃣ services(= Service / API 层)
👉 专门管接口
// systemField.js
export function queryList() {}
export function batchDelete() {}
👉 类似你后端:
Controller → Service → DAO
3.1.4. 4️⃣ hooks(= 业务逻辑复用层)
👉 React 的"高级抽象"
function useTable() {
// 封装分页 / 查询逻辑
}
3.1.5. 5️⃣ utils(= 工具类)
👉 类似 Java util
- 日期处理
- 权限判断
- token 处理
3.1.6. 6️⃣ router(= 路由)
👉 使用:React Router
<Route path="/system-field" element={<SystemField />} />
3.1.7. 7️⃣ store(= 全局状态)
👉 用户信息 / 权限 / 全局数据
3.2. 企业级进阶结构(推荐)
当项目变大时👇
3.2.1. 🔥 "按业务模块拆分"(更高级)
src/
├── modules/
│ ├── systemField/
│ │ ├── pages/
│ │ ├── components/
│ │ ├── service.js
│ │ └── hooks.js
│ ├── user/
│ └── order/
👉 优点:
- 高内聚
- 易扩展
- 团队协作更清晰
3.3. 你当前场景(风控系统)推荐结构
你现在做的是:👉 特征变量管理 + 风控系统,建议直接这样👇
src/
├── modules/
│ ├── systemField/
│ │ ├── pages/
│ │ │ └── index.jsx # 列表页
│ │ ├── components/
│ │ │ ├── EditModal.jsx
│ │ │ └── BatchDelete.jsx
│ │ ├── service.js # 对接你的后端接口
│ │ └── hooks.js # 封装列表逻辑
3.4. 接口层标准写法(非常关键)
// services/systemField.js
import request from "./request";
export function querySystemFields(params) {
return request.post("/systemFields/query", params);
}
export function batchDeleteSystemFields(data) {
return request.post("/systemFields/batch/delete", data);
}
👉 完美对接你刚才那个接口👇
{
"nameList": ["field1", "field2"]
}
3.5. 最容易踩的坑(你必须避免)
3.5.1. ❌ 1. 所有代码写在 pages(大坑)
👉 会变成 2000 行文件
3.5.2. ❌ 2. 不分 service 层
👉 页面直接写 fetch(不可维护)
3.5.3. ❌ 3. 不拆组件
👉 UI 复用性为 0
3.6. 工具类 和通用组件有什么区别? 分别是哪些内容?
utils = 处理"数据/逻辑"
components = 处理"界面/UI"
3.6.1. utils(工具类)是什么?
一堆"纯函数",只做计算/处理,不涉及页面
示例
// utils/format.js
export function formatDate(date) {
return new Date(date).toLocaleString();
}
// utils/auth.js
export function getToken() {
return localStorage.getItem("token");
}
特点
- ❌ 不涉及 JSX
- ❌ 不操作 UI
- ✅ 纯 JS 函数
- ✅ 可复用
- ✅ 无副作用(最好)
用途
- 格式化数据(时间、金额)
- token 处理
- 加密/解密
- 参数拼接
- 校验逻辑
3.6.2. components(通用组件)是什么?
一段"可复用的 UI + 交互"
📦 示例
// components/MyButton.jsx
export default function MyButton({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
📌 特点
- ✅ 有 JSX(HTML)
- ✅ 有 UI
- ✅ 有交互(点击、输入)
- ❌ 不只是函数(是组件)
🎯 用途
- 按钮
- 表格
- 弹窗
- 表单组件
3.6.3. "这个东西需要渲染页面吗?"
3.6.3.1. 需要 UI → components
<button>点我</button>
3.6.3.2. 不需要 UI → utils
formatDate()
4. React生命周期理解
React 的"生命周期"本质就是:组件从创建 → 更新 → 销毁的整个过程
但要注意一点:在现代 React 中(函数组件 + Hooks),生命周期不再用"钩子函数名称",而是用 useEffect****来表达。
4.1. ✅ 生命周期本质(先建立正确认知)
组件 = 一个函数
生命周期 = 这个函数"什么时候执行 + 做什么事"
4.2. ✅ 三大生命周期阶段(核心)
4.2.1. 1️⃣ 挂载(Mount)------组件第一次出现
👉相当于:
页面加载 / 组件第一次渲染
4.2.1.1. 📌 典型场景
- 请求接口
- 初始化数据
4.2.1.2. ✅ 写法(最重要)
useEffect(() => {
console.log("组件加载");
}, []);
👉**[]**表示:只执行一次
4.2.2. 2️⃣ 更新(Update)------数据变化
👉相当于:
state / props 变化 → 重新渲染
4.2.2.1. 📌 典型场景
- 搜索条件变化重新请求
- 表单变化联动
4.2.2.2. ✅ 写法
useEffect(() => {
console.log("count变化了");
}, [count]);
👉只有 count****变了才执行
4.2.3. 3️⃣ 卸载(Unmount)------组件被销毁
👉相当于:
页面离开 / 组件被移除
4.2.3.1. 📌 典型场景
- 清理定时器
- 取消请求
- 解绑事件
4.2.3.2. ✅ 写法
useEffect(() => {
return () => {
console.log("组件卸载");
};
}, []);
4.3. ✅ 完整生命周期写法(你必须掌握)
useEffect(() => {
console.log("挂载");
return () => {
console.log("卸载");
};
}, []);
useEffect(() => {
console.log("更新");
}, [count]);
4.4. ✅ 执行顺序(非常重要)
4.4.1. 第一次渲染:
1. 执行组件函数
2. 渲染 UI
3. 执行 useEffect(挂载)
4.4.2. 更新时:
1. state 改变
2. 重新执行组件函数
3. 重新渲染 UI
4. 执行 useEffect(更新)
4.4.3. 卸载时:
执行 cleanup(return 函数)
4.5. ✅ 类组件 vs 函数组件(理解差异)
4.5.1. ❌ 旧写法(类组件)
componentDidMount()
componentDidUpdate()
componentWillUnmount()
4.5.2. ✅ 新写法(Hooks)
全部用一个:
useEffect()
4.6. ✅ 你必须理解的关键点(重点)
4.6.1. ✔ React 没有"生命周期函数"
只有 useEffect(副作用)
4.6.2. ✔ useEffect 控制执行时机
|------------------------|---------------|
| 写法 | 含义 |
| useEffect(fn) | 每次渲染执行 |
| useEffect(fn, []) | 只执行一次(挂载) |
| useEffect(fn, [x]) | x 变才执行 |
4.6.3. ✔ return = 清理函数
return () => {}
👉相当于:
componentWillUnmount
4.7. ✅ 结合你现在做的系统(非常实用)
你做风控系统,常见写法
4.7.1. 查询列表(挂载执行)
useEffect(() => {
fetchList();
}, []);
4.7.2. 搜索条件变化(更新执行)
useEffect(() => {
fetchList();
}, [query]);
4.7.3. 页面离开(清理)
useEffect(() => {
const timer = setInterval(() => {}, 1000);
return () => clearInterval(timer);
}, []);
5. 解析const [count, setCount] = useState(0)
React 没有 get 方法
count 本身就是"当前值"
这行代码本质是什么?
const [count, setCount] = useState(0);
可以理解为:
count = 当前值(类似 get)
setCount = 修改方法(类似 set)
怎么"获取值"?
直接用变量:
<p>{count}</p>
或者:
console.log(count);
❗没有这种写法:
count.get() ❌
setCount 是怎么工作的?(重点)
setCount(count + 1);
做了两件事:
1. 更新状态
2. 触发组件重新执行(重新渲染)
然后:
function MyComponent() {
const [count, setCount] = useState(0);
}
会重新执行一遍,新的:
count = 更新后的值
6. React中 Hook函数
在 React 中:
Hook = 让函数组件拥有"状态 / 生命周期 / 逻辑复用能力"
统一特征:
都以 use 开头
这些是你能写页面必须会的。
6.1. 1️⃣ useState(状态)
const [count, setCount] = useState(0);
作用:组件数据
6.2. 2️⃣ useEffect(生命周期/副作用)
useEffect(() => {
fetchData();
}, []);
作用:
- 请求接口
- 监听变化
- 清理资源
6.3. 3️⃣ useRef(非常重要)
const inputRef = useRef(null);
作用:
1. 获取 DOM
2. 保存变量(不会触发渲染)
示例
<input ref={inputRef} />
6.4. 4️⃣ useContext(跨组件传值)
const value = useContext(MyContext);
作用:
替代 props 一层层传递
相当于是vue里面 useContext ≈ Vue 的 provide / inject (跨组件传递工作)
React 写法
const UserContext = createContext();
function App() {
return (
<UserContext.Provider value={{ name: "Tom" }}>
<Child />
</UserContext.Provider>
);
}
function Child() {
const user = useContext(UserContext);
return <div>{user.name}</div>;
}
Vue 写法
// 父组件
provide("user", { name: "Tom" });
// 子组件
const user = inject("user");
效果一样:子组件直接拿到父组件数据(跨层级)
6.5. 5️⃣ useMemo(缓存计算结果)
const result = useMemo(() => {
return expensiveCalc(a, b);
}, [a, b]);
作用:避免重复计算
6.6. 6️⃣ useCallback(缓存函数)
const handleClick = useCallback(() => {
console.log("click");
}, []);
作用:避免函数重复创建(优化性能)
6.7. 7️⃣ useReducer(复杂状态)
类似 Redux
const [state, dispatch] = useReducer(reducer, initialState);
场景:
- 表单复杂
- 多状态联动
6.8. 8️⃣ useLayoutEffect
和 useEffect 类似,但:
在 DOM 渲染前执行
场景:
- 操作 DOM
- 防止闪烁
6.9. 9️⃣ useImperativeHandle
配合 forwardRef 用
很少用(组件暴露方法)
6.10. 🔟 useDebugValue
调试用(开发者工具)
7. React 相关思考
7.1. React和vue 核心思想是不是一样?
可以这么说:React 和 Vue.js 在"核心思想层面是相似的",但在"实现哲学和开发体验上差异很大"。
7.1.1. 核心思想:确实"基本一致" ✅
两者共享的核心理念:
7.1.1.1. 1️⃣ 数据驱动视图(本质一致)
数据变化 → UI 自动更新
和你后端类比:
- Java:对象 → JSON → 页面
- 前端:state/data → render → UI
7.1.1.2. 2️⃣ 组件化开发(完全一致)
页面 = 组件树
- Button / Table / Form 全是组件
- 可复用、可组合
7.1.1.3. 3️⃣ 单向数据流(核心一致)
父组件 → 子组件(props)
👉 这点两者完全一样。
7.1.2. 核心差异(重点)⚠️
7.1.2.1. 1️⃣ 思维方式差异(最大区别)
|----|-------------------|---------------------|
| | React | Vue |
| 思想 | 函数式 / JS 驱动 | 模板驱动(HTML思维) |
| 写法 | JSX(JS + HTML 混写) | template(HTML + 指令) |
| 感觉 | 更"程序员" | 更"前端工程师" |
React
{list.map(item => <div>{item}</div>)}
👉 完全 JS 思维
Vue
<div v-for="item in list">{{ item }}</div>
👉 类似模板语言
7.1.2.2. 2️⃣ 响应式机制(本质不同)
Vue(自动响应式)
data() {
return { count: 0 }
}
👉 改值就更新:
this.count++
React(手动触发)
const [count, setCount] = useState(0);
setCount(count + 1);
👉 ❗必须手动 set
7.1.2.3. 3️⃣ 数据绑定方式
Vue:双向绑定(强)
<input v-model="value" />
React:单向 + 手动
<input value={value} onChange={e => setValue(e.target.value)} />
👉 React 更"可控",但更啰嗦。
7.1.2.4. 4️⃣ 生态设计理念
|------|------------------|----------------|
| | React | Vue |
| 定位 | UI 库 | 渐进式框架 |
| 官方提供 | 很少 | 很完整 |
| 路由 | 外部(React Router) | 官方(Vue Router) |
| 状态管理 | Redux / Zustand | Vuex / Pinia |
👉 简单说:
- React:"给你积木,自己搭"
- Vue:"给你一整套房子"
7.2. React中useState 与Vue中Vuex/Pinia的区别
useState = 组件内状态(局部)
Vuex/Pinia = 全局状态管理(跨组件)
|-------|----------|--------------|
| 维度 | useState | Vuex / Pinia |
| 作用范围 | 当前组件 | 全局 |
| 数据共享 | ❌ 不行 | ✅ 可以 |
| 生命周期 | 组件级 | 应用级 |
| 使用复杂度 | 简单 | 较复杂 |
| 典型场景 | 表单 / 按钮 | 用户信息 / 权限 |
7.2.1. 在 React 中 useState:
import { useState } from 'react';
const [count, setCount] = useState(0);
作用:
给"当前组件"一个状态
7.2.2. 📌 特点
- 只属于当前组件
- 组件销毁就没了
- 不能直接跨组件共享(除非传 props)
7.2.3. Vue中Vuex / Pinia 是什么
在 Vue.js 生态里:
- Vuex(旧)
- Pinia(新)
作用:
全局状态管理(所有组件都能用)
7.2.4. 📌 示例(Pinia)
export const useUserStore = defineStore('user', {
state: () => ({
name: 'Tom'
})
});
👉 任意组件都能用:
const userStore = useUserStore();