做全栈开发的小伙伴可能都有过这种经历:前端页面搭好了大半,后端接口还在排期;好不容易等后端接口上线,联调时发现数据格式和预期差了十万八千里。这种 "前后端不同步" 的痛,在 React 项目里尤其明显 ------ 组件状态、数据流都搭好了,就差数据来驱动,只能对着空页面发呆。
但自从我在项目里用了 Mock,这种尴尬局面就再也没出现过。今天跟大家聊聊 Mock 到底怎么玩才能让前后端协作效率翻倍。
为什么 React 项目更需要 Mock?
React 项目的组件化开发模式,决定了我们经常需要基于数据结构设计组件。比如一个 TodoList 组件,得知道每条 todo 的 id、title、completed 这些字段才能动手。但现实往往是:产品经理催着出原型,后端说 "接口下周才能好"。
这时候 Mock 就成了救星 ------ 它能帮我们在没有后端接口的情况下,先定义好数据格式,让组件开发、状态管理、交互逻辑都能正常推进。等后端接口 ready 后,只需要切换一下数据源,整个流程无缝衔接。
就像我最近做的表演型项目,前端用 React,后端计划用 Node.js。立项会上定好接口文档后,我当天就用 Mock 把所有接口模拟出来了,等后端一周后完成接口开发时,我的前端页面已经能完美运行,联调只用了半天就搞定。
在 React+Vite 项目中配置 Mock
既然是 Vite+React 项目,那 vite-plugin-mock 肯定是首选方案,配置起来比传统方式简单太多。
首先安装依赖:
bash
npm install mockjs vite-plugin-mock --save-dev
然后在 vite.config.js 里配置插件:
js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig({
plugins: [
react(),
viteMockServe({
mockPath: './mock', // 存放mock文件的目录
localEnabled: true, // 开发环境启用mock
prodEnabled: false, // 生产环境关闭mock
supportTs: false // 是否支持TypeScript
})
]
})
接着在项目根目录创建 mock 文件夹,新建 test.js 文件:
js
// mock/test.js
export default [
{
url: '/api/todos',
method: 'get',
response: () => {
// 模拟返回数据
return {
code: 0,
message: 'success',
data: [
{ id: 1, title: '完成Mock配置', completed: true },
{ id: 2, title: '开发Todo组件', completed: false }
]
}
}
}
]
启动项目后,访问http://localhost:5173/api/todos,就能看到模拟的数据了。这时候在 React 组件里用 axios 请求这个接口,完全和真实接口一样:
jsx
import { useEffect, useState } from 'react';
import axios from 'axios';
function TodoList() {
const [todos, setTodos] = useState([]);
useEffect(() => {
axios.get('/api/todos').then(res => {
setTodos(res.data.data);
});
}, []);
return (
<ul>
{todos.map(todo => (
<li key={todo.id} style={{ textDecoration: todo.completed? 'line-through' : 'none' }}>
{todo.title}
</li>
))}
</ul>
);
}
这段代码写完,就算后端还没开始动工,我们的 TodoList 已经能正常展示数据了。
Mock 进阶技巧
基础配置很简单,但要让 Mock 真正发挥作用,还得掌握这些实用技巧。
1.数据模板定义和占位符
Mock.js 最强大的地方就是它的数据模板定义,掌握了这个,你就能生成各种想要的数据。
基本语法是'属性名|生成规则': 属性值
。 比如,我们需要模拟一个获取用户列表的接口,并且列表中的数据是随机生成的。我们可以这样编写 Mock 文件:
js
import Mock from 'mockjs';
export default [
{
url: '/api/users',
method: 'get',
response: () => {
const users = Mock.mock({
'list|5-10': [
{
'id|+1': 1,
'name': '@cname',
'age|18-60': 1,
'email': '@email',
'date': '@date(yyyy-MM-dd)',
'image': '@image(200x100)',
'paragraph': '@cparagraph(3, 5)'
},
],
});
return {
code: 0,
message: 'success',
data: users.list,
};
},
},
];
在这段代码中,我们使用了 Mock.js 的强大语法来生成随机数据。'list|5-10
' 表示生成一个包含 5 到 10 个元素的数组,每个元素都是一个用户对象。'id|+1
': 1 表示 id 从 1 开始自增,'name': '@cname
' 表示生成一个随机的中文名,'age|18-60
': 1 表示生成一个 18 到 60 之间的随机年龄,'email': '@email
' 表示生成一个随机的邮箱地址,'date': '@date(yyyy-MM-dd)
' 表示生成'yyyy-MM-dd'格式的日期, 'image': '@image(200x100)
' 表示生成一张200*100的图片, 'paragraph': '@cparagraph(3, 5)
'表示生成3-5段中文段落 。
这样,当我们前端发起 /api/users 的请求时,Mock.js 会返回一个包含随机用户信息的列表,满足我们更复杂的业务需求。
2. 动态返回数据
真实接口往往会根据请求参数返回不同数据。比如获取单个 todo 详情的接口,需要根据 id 返回对应数据:
js
// mock/todo.js
export default [
{
url: '/api/todos/:id', // 带参数的接口
method: 'get',
response: (req) => {
const { id } = req.params; // 获取url参数
// 模拟数据库查询
const todoList = [
{ id: 1, title: '学习Mock', completed: false },
{ id: 2, title: '开发组件', completed: true }
];
const target = todoList.find(item => item.id === Number(id));
return {
code: target? 0 : 404,
message: target? 'success' : '未找到该todo',
data: target || null
};
}
}
]
3. 处理不同请求类型
实际开发中接口请求类型多样,除了常见的 GET,还有 POST、PUT、DELETE 等,Mock 都能妥善处理。比如处理 POST 请求:
js
// mock/todo.js 新增POST接口
{
url: '/api/todos',
method: 'post',
response: (req) => {
const { title } = req.body; // 获取请求体数据
if (!title) {
return { code: 1, message: '标题不能为空', data: null };
}
// 模拟新增数据
return {
code: 0,
message: '添加成功',
data: { id: Date.now(), title, completed: false }
};
}
}
在 React 组件里调用时和真实接口完全一样:
jsx
const addTodo = async (title) => {
try {
const res = await axios.post('/api/todos', { title });
if (res.data.code === 0) {
setTodos(prevTodos => [...prevTodos, res.data.data]);
}
} catch (error) {
console.error('添加失败:', error);
}
};
4. 模拟加载状态
真实网络请求有延迟,我们可以在 Mock 里设置响应时间,测试加载状态:
js
// 在vite.config.js中配置全局延迟
viteMockServe({
// 其他配置...
delay: 500 // 所有接口延迟500ms返回
})
这样就能在组件里测试 loading 状态的展示效果,让用户体验更贴近真实场景。
5.区分环境使用
在实际项目中,我们通常希望开发环境使用 Mock 数据,生产环境则调用真实接口。可以通过环境变量来控制:
js
// 在mock/index.js中
if (process.env.NODE_ENV === 'development') {
// 只在开发环境加载Mock配置
import './user.js';
import './goods.js';
}
然后在 package.json 的 scripts 中配置环境变量:
json
"scripts": {
"start": "REACT_APP_ENV=development react-scripts start",
"build": "REACT_APP_ENV=production react-scripts build"
}
6.Mock 与 React 状态管理结合
在使用 Redux、MobX 等状态管理库的 React 项目中,Mock 数据也能无缝融入。以 Redux 为例,异步 action 获取 Mock 数据的方式和真实接口一致:
js
// actions/userActions.js
import axios from 'axios';
export const fetchUser = (id) => {
return async (dispatch) => {
dispatch({ type: 'FETCH_USER_START' });
try {
const res = await axios.get(`/api/user?id=${id}`);
dispatch({
type: 'FETCH_USER_SUCCESS',
payload: res.data.data
});
} catch (err) {
dispatch({
type: 'FETCH_USER_ERROR',
payload: err.message
});
}
};
};
组件中调用 action 的代码完全不用考虑数据来源是 Mock 还是真实接口,这种一致性让状态管理逻辑更纯粹。
前后端联调
当后端接口开发完成后,我们需要进行前后端联调。此时,我们只需要将 vite.config.js 中的 prodEnabled 设置为 false,关闭 Mock.js 的功能,前端请求就会直接发送到后端真实接口。在联调过程中,如果发现数据格式不一致等问题,我们可以及时与后端沟通调整,确保项目的顺利进行。
总结
用好Mock 让前端开发从 "被动等待" 变成 "主动推进"。尤其是在 React 项目中,提前用 Mock 定义好数据结构,能让组件设计更合理,状态管理更清晰。
你们项目里有什么 Mock 的骚操作?欢迎在评论区分享,让我也取取经~