1. dispatch 同一个 action 在极短的时间内 2 次 如果 reducer 里面是用的return fromJS(action.payload)
,然后 dispatch 同一个 action 在极短的时间内 2 次,导致的结果就是第二次使用的 immutable state 是旧的,它没有被第一次的 action 所更改,这样的后果就是状态丢失了。JS 执行时单线程,所以 reudx 这里并没有 race condition,真正的原因是这两次 dispatch 是在同一 render 桢中运行的,所以它们 mapStateToProps 中原始 state 是相同的,事实上就是第二次修改覆盖了第一次修改(reducer 中使用了 fromJS,而非 mergeDeep)。
解决方案:
多个 action 修改不同部分
多个修改合并到一个 action 我先选择#2
2. yield select 连续多个 好像如果有一个循环,大约 100 多次,在循环体里面 yield select(selctor), 那么可能导致 saga 不工作,但是 redux 还是工作的。
3. redux-persist-immutable 这个库会把 Immutable.List 成员中的 undefined 变为 null,但是 Immutable.Map 中我不清楚。 因为我们遇到一个 undefined 被 redux-persist-immutable 转为 null 存储了,这就是这个 bug 难以推断的原因。
redux-immutable 可以设置 redux 的根节点是 Immutable.Map,但是这个必要性我还不清楚,好像有性能优势。
redux-persist 可以持久化 redux 的数据,可以设置白名单, 默认序列化是用 JOSN.stringify, 反序列化是 JSON.parse。
redux-persist-immutable 可以持久化 redux 中 Immutable 类型的数据,如 Map,List,transform 用的是 redux-persist-transform-immutable。
redux-persist-transform-immutable,这个库很简单,就是做 Immutable 的序列化,反序列化,它包装成一个 redux-persist 的 transform。
redux-persist-transform-immutable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 var transit = require ("transit-immutable-js" );var reduxPersist = require ("redux-persist" );module .exports = function (config ) { config = config || {}; var transitInstance = transit; if (config.records ) { transitInstance = transit.withRecords (config.records ); } return reduxPersist.createTransform ( function (state ) { return transitInstance.toJSON (state); }, function (raw ) { return transitInstance.fromJSON (raw); }, config ); };
transit-immutable-js 这个是序列化和反序列化Immutable类型的工具库,它依赖 transit-js。
transit-js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 writer.marshal = function (em, obj, asMapKey, cache ) { if (em.transform !== null ) { obj = em.transform (obj); } var h = em.handler (obj) || (em.handlerForForeign ? em.handlerForForeign (obj, em.handlers ) : null ), tag = h ? h.tag (obj) : null , rep = h ? h.rep (obj) : null ; if (h != null && tag != null ) { switch (tag) { case "_" : return em.emitNil (asMapKey, cache); break ; default : return writer.emitEncoded (em, h, tag, rep, obj, asMapKey, cache); break ; } } }; writer.JSONMarshaller .prototype .handler = function (obj ) { var h = this .handlers .get (handlers.constructor (obj )); }; handlers.constructor = function (x ) { if (x == null ) { return null ; } }; handlers.defaultHandlers = function (hs ) { hs.set (null , new handlers.NilHandler ()); hs.set (String , new handlers.StringHandler ()); return hs; }; writer.JSONMarshaller .prototype .emitNil = function (asMapKey, cache ) { if (asMapKey) { return this .emitString (d.ESC , "_" , "" , asMapKey, cache); } else { return null ; } }; handlers.NilHandler = function Transit$NilHandler ( ) {}; handlers.NilHandler .prototype .tag = function (v ) { return "_" ; }; handlers.NilHandler .prototype .rep = function (v ) { return null ; }; handlers.NilHandler .prototype .stringRep = function (v ) { return "null" ; };
4. Redux-Saga中的takeLatest
如果函数fun1定义是generator,那么调用的时候需要用yield func1()
。直接fun1()
是不会执行的。
takeLatest会取消上一次执行的generator中的effects,并且递归取消其子generator中的effects。但是有一点要注意,async或promise不受影响,它们不会被取消,而是会继续执行。 所以sgaa中的cancel只是让generator立即返回,但是async和promise不会受到影响。所以我们在写generator的时候,尽量使用effects,当遇到promise调用的时候,使用call去调用,这样就会被cancel.