小程序数据层方案怎么选?真实项目里我这样搭

做小程序开发时,很多人一上来就猛写页面逻辑,等加到第5个页面、第3个接口、第2个缓存策略,突然发现:用户登录态丢了、购物车数据不同步、首页加载慢得像在等泡面——问题不在UI,而在数据层没理清楚。

什么是数据层?别被名字吓住

简单说,就是把“数据从哪来、怎么存、谁在用、怎么更新”这一套拎出来单独管。不是非得搞多高大上,而是让 data-fetch、storage、state 更新这三件事不散落在每个 Page 里互相打架。

常见踩坑现场

比如你写了个商品详情页,顺手 wx.setStorageSync('cart', cartData);又在购物车页自己再读一遍、改一遍、再存一遍。结果用户切后台再回来,购物车空了——因为两个页面各自操作 storage,没同步状态,也没统一错误处理。

轻量但够用的方案:基于 class 的 DataLayer

不需要引入 MobX 或 Redux,一个 DataLayer 类就能兜住大部分需求。核心就三点:统一请求封装、本地缓存代理、订阅通知。

class DataLayer {
constructor() {
this.cache = new Map();
this.subscribers = new Map();
}

async fetchProduct(id) {
const cacheKey = `product_${id}`;
if (this.cache.has(cacheKey)) return this.cache.get(cacheKey);

const res = await wx.request({
url: `/api/product/${id}`,
method: 'GET'
});
if (res.data?.code === 0) {
this.cache.set(cacheKey, res.data.data);
this.notify(cacheKey, res.data.data);
return res.data.data;
}
}

subscribe(key, cb) {
if (!this.subscribers.has(key)) this.subscribers.set(key, []);
this.subscribers.get(key).push(cb);
}

notify(key, data) {
const cbs = this.subscribers.get(key) || [];
cbs.forEach(cb => cb(data));
}
}

在页面 onLoad 里:

const dl = new DataLayer();

Page({
data: { product: null },

onLoad() {
dl.subscribe('product_123', (data) => {
this.setData({ product: data });
});
dl.fetchProduct(123);
}
});

进阶一点:加一层本地持久化

登录态、用户偏好、未提交的表单草稿,这些不能只靠内存 cache。我们给 DataLayer 加个 persist 方法:

async persist(key, value) {
try {
await wx.setStorage({ key, data: JSON.stringify(value) });
} catch (e) {
console.warn('persist failed:', e);
}
}

async restore(key) {
try {
const res = await wx.getStorage({ key });
return JSON.parse(res.data);
} catch (e) {
return null;
}
}

登录后调用 dl.persist('user_info', userInfo),下次打开页面直接 dl.restore('user_info') 拿,比每次 wx.getStorageSync 安全又干净。

什么时候该换更重的方案?

如果你的小程序已经接入多个服务(订单+IM+直播+会员),且团队超过3人协作,那可以考虑 Taro + Zustand,或者原生小程序 + miniprogram-data-parser。但90%的工具类、电商类小程序,上面那个 class 方案真够用了——上线前压测过 200+ 页面,没出过数据错乱。

最后提醒一句:别为了“架构漂亮”提前过度设计。先跑通 login → home → detail → cart 这条链路的数据流,再慢慢抽离、加固、加日志。数据层不是摆设,是帮你少修半夜线上 bug 的那堵墙。