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

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

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

相关推荐
人工智能训练6 小时前
【极速部署】Ubuntu24.04+CUDA13.0 玩转 VLLM 0.15.0:预编译 Wheel 包 GPU 版安装全攻略
运维·前端·人工智能·python·ai编程·cuda·vllm
会跑的葫芦怪7 小时前
若依Vue 项目多子路径配置
前端·javascript·vue.js
pas13610 小时前
40-mini-vue 实现三种联合类型
前端·javascript·vue.js
摇滚侠10 小时前
2 小时快速入门 ES6 基础视频教程
前端·ecmascript·es6
珑墨10 小时前
【Turbo】使用介绍
前端
军军君0111 小时前
Three.js基础功能学习十三:太阳系实例上
前端·javascript·vue.js·学习·3d·前端框架·three
打小就很皮...12 小时前
Tesseract.js OCR 中文识别
前端·react.js·ocr
wuhen_n12 小时前
JavaScript内存管理与执行上下文
前端·javascript
Hi_kenyon13 小时前
理解vue中的ref
前端·javascript·vue.js
落霞的思绪14 小时前
配置React和React-dom为CDN引入
前端·react.js·前端框架