👀 我们先来看一段没有使用数据字典的代码
javascript
go
// 看到这段代码,你什么感受?
if (user.type === 1) {
// ...
} else if (user.type === 2) {
// ...
}
内心os: "这1和2到底是什么?这我得去问多少人呀!"
javascript
ini
//当我们需求要把'禁用'改成'冻结',把状态值从1改成2
if (user.status === 1) {
return '禁用'; // 这里要改
}
<Option value={1}>禁用</Option> // 这里要改
const disabledUsers = users.filter(u => u.status === 1); // 这里要改
内心os: "这到底是什么破代码!"
🎉 那用了数据字典后是什么样的呢?
javascript
css
if (user.type === USER_TYPE.VIP){
// 奥奥,原来是vip用户!
}
const USER_STATUS = {
NORMAL: { value: 0, label: '正常' },
DISABLED: { value: 2, label: '冻结' } // 这里value从1改成2,label从'禁用'改成'冻结'
};
内心os: "天呐!好方便!"
所以,数据字典的真正作用是:让我们写的代码,既能被机器正确执行,也能被人轻松读懂。
🏠 那数据字典存储在哪里呢?
javascript
css
// 刚开始,我觉得把字典写死在前端简直太方便了
export const DEPARTMENT = {
TECH: { value: 1, label: '技术部' },
PRODUCT: { value: 2, label: '产品部' },
DESIGN: { value: 3, label: '设计部' },
OPERATION: { value: 4, label: '运营部' }
};
内心os: "一次定义,到处使用,美滋滋!没有网络请求,性能杠杠的!代码清晰,类型安全,完美!"
javascript
css
export const USER_ROLE = {
ADMIN: { value: 1, label: '管理员' },
USER: { value: 2, label: '普通用户' },
GUEST: { value: 3, label: '访客' }
};
💥 那么此时问题来了
问题1: 如果现在的需求变了,要把技术部分为前端部和后端部。哦!这简直是个灾难。因为所有的业务也跟着变化!那我要改到什么时候!!
问题2: 如果我现在想在USER_Role里面添加一个审核员的角色,那现在value值要写多少呢?4?会不会和后台冲突?
- 后端也要同步改,前后端要一起上线!
- 如果后端先上线,前端还没改,就显示不出来!
- 如果前端先上线,后端还没改,就会报错!
🎯 所以什么适合写死在前端呢?
✅ 适合写死在前端的(不会变的)
javascript
css
// 1. 通用状态枚举(业务逻辑相关)
export const ORDER_STATUS = {
PENDING: { value: 1, label: '待支付' },
PAID: { value: 2, label: '已支付' },
COMPLETED: { value: 3, label: '已完成' },
CANCELLED: { value: 4, label: '已取消' }
};
// 理由:这些状态与业务逻辑强相关,基本不会改变
// 2. 界面状态
export const BUTTON_SIZE = {
SMALL: { value: 'small', label: '小' },
LARGE: { value: 'large', label: '大' }
};
// 理由:纯前端控制,与后端无关
// 3. 颜色、样式映射
export const STATUS_COLOR = {
SUCCESS: { value: 'success', color: '#52c41a' },
ERROR: { value: 'error', color: '#ff4d4f' },
WARNING: { value: 'warning', color: '#faad14' }
};
// 理由:纯前端显示逻辑
❌ 不适合写死在前端的
javascript
scss
// 1. 组织架构数据
export const DEPARTMENT = {
TECH: { value: 1, label: '技术部' },
PRODUCT: { value: 2, label: '产品部' }
};
// 应该从后端获取
const [departments, setDepartments] = useState([]);
useEffect(() => {
api.getDepartments().then(setDepartments);
}, []);
// 2. 分类标签数据
export const ARTICLE_CATEGORY = {
TECH: { value: 1, label: '技术文章' },
NEWS: { value: 2, label: '公司新闻' }
};
const [categories, setCategories] = useState([]);
useEffect(() => {
api.getArticleCategories().then(setCategories);
}, []);
// 3. 权限角色数据
export const USER_ROLE = {
ADMIN: { value: 1, label: '管理员' },
USER: { value: 2, label: '普通用户' }
};
// 应该由后端管理
const [roles, setRoles] = useState([]);
useEffect(() => {
api.getRoles().then(setRoles);
}, []);
🤔 既然明白了字典的存储,那又有一个问题了。前端要怎么样去管理后端返回的数据字典呢?
在思考这个问题之前,我们先来思考一个问题:我们为什么要去管理后端返回的数据字典呢?
在实际开发中,一个常见的痛点是:同一个字典数据(如"用户状态"、"部门列表")可能在应用的多个组件或模块中被使用 。如果每个使用的地方都独立发起请求,会导致对同一个接口的重复调用。
这会带来三个问题:
- 增加服务端压力和网络开销
- 可能导致数据不一致(如果多次请求之间数据更新了)
- 影响用户体验,用户会反复看到Loading状态
因此,一个高效的策略是引入前端缓存机制。它的工作流程如下:
- 当需要某个字典数据时(例如
userStatus),前端首先检查缓存中是否存在 - 如果缓存中存在,则直接返回该数据
- 如果缓存中不存在,则向后台发起请求,获取数据后放入缓存,再返回
这套机制的核心价值在于:
- 性能优化:避免了重复请求,减轻了前后端负担
- 体验提升:缓存的读取是瞬时的,用户无需等待
- 状态统一:确保了整个应用使用的字典数据是同一份,消除了不一致的风险
🏗️ 前端要怎么样去管理后端返回的数据字典
好的,直接给出核心答案。前端管理后端字典的核心方法是:建立一套中心化的缓存机制。
1. 创建全局字典仓库
javascript
dart
// 创建一个全局的字典仓库
const dictCache = new Map(); // 使用Map存储所有字典数据
// 或者使用状态管理库
const useDictStore = create((set, get) => ({
dicts: {},
fetchDict: async (dictKey) => {
const state = get();
// 1. 先查缓存,有则直接返回
if (state.dicts[dictKey]) {
return state.dicts[dictKey];
}
// 2. 没有则请求并缓存
const data = await api.getDict(dictKey);
set({ dicts: { ...state.dicts, [dictKey]: data } });
return data;
}
}));
2. 统一接入层
javascript
scss
// 所有组件都通过这个Hook获取字典
const useDict = (dictKey) => {
const { dicts, fetchDict } = useDictStore();
useEffect(() => {
if (!dicts[dictKey]) {
fetchDict(dictKey);
}
}, [dictKey]);
return dicts[dictKey] || [];
};
3. 业务组件使用
javascript
ini
// 所有地方都这样使用
const UserForm = () => {
const departments = useDict('departments'); // 同一份数据,多个组件共享
const roles = useDict('user_roles');
return (
<select>
{departments.map(item =>
<option key={item.value} value={item.value}>{item.label}</option>
)}
</select>
);
};
📚 三层管理架构
1. 数据层 - dictCache / useDictStore
角色:数据的唯一真相来源
职责 :负责与后端通信,并在内存中持久化获取到的字典数据。它像一个全局仓库,所有字典数据都存储于此
2. 接入层 - useDict Hook
角色:连接组件与数据层的桥梁
职责 :组件不直接接触底层缓存和API,而是通过这个Hook。它封装了复杂的逻辑:首先检查缓存,若存在则立即返回,若不存在则触发请求并更新缓存
3. 展示层 - 业务组件
角色:数据的使用者
职责 :只需声明需要什么字典(如 useDict('departments')),无需关心数据从哪里来、是否已经加载过。它们总是能获得统一、一致的数据