数据字典:从"猜谜游戏"到"优雅编程"的奇幻之旅

👀 我们先来看一段没有使用数据字典的代码

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);
}, []);

🤔 既然明白了字典的存储,那又有一个问题了。前端要怎么样去管理后端返回的数据字典呢?

在思考这个问题之前,我们先来思考一个问题:我们为什么要去管理后端返回的数据字典呢?

在实际开发中,一个常见的痛点是:同一个字典数据(如"用户状态"、"部门列表")可能在应用的多个组件或模块中被使用 。如果每个使用的地方都独立发起请求,会导致对同一个接口的重复调用

这会带来三个问题:

  1. 增加服务端压力和网络开销
  2. 可能导致数据不一致(如果多次请求之间数据更新了)
  3. 影响用户体验,用户会反复看到Loading状态

因此,一个高效的策略是引入前端缓存机制。它的工作流程如下:

  1. 当需要某个字典数据时(例如 userStatus),前端首先检查缓存中是否存在
  2. 如果缓存中存在,则直接返回该数据
  3. 如果缓存中不存在,则向后台发起请求,获取数据后放入缓存,再返回

这套机制的核心价值在于:

  • 性能优化:避免了重复请求,减轻了前后端负担
  • 体验提升:缓存的读取是瞬时的,用户无需等待
  • 状态统一:确保了整个应用使用的字典数据是同一份,消除了不一致的风险

🏗️ 前端要怎么样去管理后端返回的数据字典

好的,直接给出核心答案。前端管理后端字典的核心方法是:建立一套中心化的缓存机制

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')),无需关心数据从哪里来、是否已经加载过。它们总是能获得统一、一致的数据

相关推荐
嗝屁小孩纸2 小时前
开发集成热门小游戏(vue+js)
前端·javascript·vue.js
赛博切图仔2 小时前
深入理解 package.json:前端项目的 “身份证“
前端·javascript
UIUV2 小时前
JavaScript 学习笔记:深入理解 map() 方法与面向对象特性
前端·javascript·代码规范
太平洋月光2 小时前
MJML邮件如何随宽度变化动态切换有几列📮
前端·css
AAA不会前端开发2 小时前
TypeScript核心类型系统完全指南
前端·typescript
徐同保2 小时前
使用GitKraken把feature_xtb_1104分支的多次提交记录合并到一起,只保留一次提交记录,并合并到master分支
前端
小光学长2 小时前
基于Vue的智慧楼宇报修平台设计与实现066z15wb(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
前端·数据库·vue.js
醉方休2 小时前
web前端 DSL转换技术
前端
sen_shan2 小时前
Vue3+Vite+TypeScript+Element Plus开发-27.表格页码自定义
前端·javascript·typescript