Hacking Limbo

Reading / Coding / Hacking

Immutable.js 的坑

在 Redux reducers 里尝试使用 Immutable.js, 整体印象是这个项目试图以库的方式解决语言(运行时)层面的问题,但是整合得并不够好,用起来很别扭。遇到的问题有:

  1. ListMap 与 JavaScript 原生的 ArrayObject 接口 & 语法都不兼容,比如不支持 xs[0] / obj.key 这种取值方式,更没法用 ES 2015 新增的 deconstructing, 导致切换到 Immutable 之后代码啰嗦了很多。
  2. 由于问题 1 的存在,在不引入 TypeScript / Flow 的情况下,很容易因为混淆变量类型而遇到各种奇怪的错误,比如 TypeError: xs.count is not a function.
  3. JavaScript 原生对象转换成 Immutable 对象的过程中,会陷入 "all-or-nothing" 的尴尬处境。

第 3 点再展开说一下。假设前端通过 AJAX API 请求(比如用 axios 库)拿到了一堆 JSON, 可能会这样处理:

// one of many reducers...
function onFetchComplete(state, { payload }) {
  const ids = []
  const itemsById = {}

  for (const item of payload.items) {
    const { id } = item
    ids.push(id)
    itemsById[id] = item
  }

  // state 是个 Immutable Map
  // 此处有坑!
  return state.merge({
    ids,
    itemsById,
  })
}

以上代码有个隐藏的坑,即 state.merge()idsitemsById 转换成了 Immutable 对象。文档里是这样说的(一开始没注意,后来 debug 的时候才发现):

If any of the values provided to merge are not Collection (would return false for isCollection) then they are deeply converted via fromJS before being merged.

考虑到短期的成本 / 收益,尝试不到一个星期就放弃了(还好前端项目暂时只有我一个人写 💩),相关问题也没有再深究,之后有精力会再重新考虑一下。