bug 描述
还是很久之前在准备使用redux devtool的时候,结果安装好插件之后,令人崩溃的事情就出现了,整个浏览器立马崩了,再加上mac的电风扇本来就差,嗡嗡的令人崩溃。
当时加上项目比较忙,所以暂时就没有使用redux devtool来进行调试,最近找了点时间,准备重新看下,毕竟放着也不是个事。
switch (action.type) {
case GET_SIDEMENU_CONFIG_SUC:
console.log(
"%c===========begin=========",
"background: #000; color: #bada55"
);
console.log("ddsd");
console.log(
"%c===========end==========",
"background: #000; color: #bada55"
);
return update(state, { $set: transForm(action.payload) });
default:
return state;
}
[站外图片上传中...(image-e08f3-1550837612008)]
可以看到在疯狂的发dispatch请求,结果就是导致浏览器崩溃,内存耗尽。
问题分析
1,刚开始以为是action里边这里有个比较复杂的转换逻辑函数影响的,排查了不是。
2,觉得是不是一直代码里边有循环一直在发,全局搜了下,唯一的一次dispatch的时候,就是在请求成功的时候,但是请求了一次之后,就不会有任何地方在重新dispatch了。
3,然后就在测试是不是action.type有问题,是不是名字和redux devtool有冲突,改过来改过去,没解决问题。
4,最后干脆想直接删除该SIDEMENU的dispacth,可是现在竟然变成了其它的action.type在疯狂的接受了。
5,后来一想这么搞不是办法,删了一个又来了一个,还是到源头那边去搞,于是直接到了router那边去看。
router那边的代码如下:
}
>
{/* */}
当然这是简化之后的,asyncComp 是用来动态的加载reducer和component的,可是就算这样简化之后,仍然是浏览器死机。
6,然后就想是不是和这段代码有关系,于是去把这段代码
}
>
{/* */}
替换成这样的代码
ddss
结果是好的,页面现在正常了,
于是就想是不是和asyncComp这个函数有关系呢,于是就去看了下函数
const asyncComp = (store, modName, config = { extra: [] }) => props => {
const Comp = lazy(() => {
const modKey = modName;
const keys = [modName, ...config.extra];
const reducers = keys.map(key => {
return import(`../reducers/${key}/index`);
});
return Promise.all(reducers)
.then(result => {
injectReducer(store, { keys, reducers: result });
return import(/* webpackChunkName: "[request]" */ `./${modName}`);
})
.catch(error => console.error(`asyncComp${error}`));
});
return ;
};
感觉没什么问题,然后就在injectReducer的地方,打了断点,果然他妈的疯狂的在触发,不断的触发,不断的触发,现在可以得出判断上面不断触发action.type是因为不断的插入reducer。
到了这里因为是injectReducer的问题
injectReducer的代码如下:
export const injectReducer = (store, { key, reducer, keys, reducers }) => {
// 针对一个组件中有多个store
if (keys && reducers) {
keys.forEach((key, index) => {
store.asyncReducers[key] = reducers[index].default;
});
} else {
store.asyncReducers[key] = reducer;
}
store.replaceReducer(makeRootReducer(store.asyncReducers));
};
感觉也没什么问题,不过这里看到了不断的replaceReducer,感觉应该和replaceReducer有关系。
7,google了下redux devtool 导致不断的dispatch的问题,好像也没有头绪,资料也很少,于是到redux devtool的github下找issuse,也没有什么类似的,于是去看了下faq,发现这样一段
@@INIT or REPLACE action resets the state of the app or last actions RE-APPLIED
@@redux/REPLACE
(or @@INIT
) is used internally when the application is hot reloaded. When you use store.replaceReducer
the effect will be the same as for hot-reloading, where the extension is recomputing all the history again. To avoid that set shouldHotReload
parameter to false
.
于是就找到了解决办法,就是得设置shouldhotreload为false
代码如下:
const composeEnhancers = composeWithDevTools({
shouldHotReload: false
});
const store = createStore(
combineReducers({
Common: commonReducer
}),
initialState,
composeEnhancers(applyMiddleware(...middleware))
);
问题得到解决。
反思
1,这个问题按说应该很多人可以遇到,hot-reload和redux和redux devtool应该好多人使用,可是为什么网上竟然没什么资料。
2,其实一开始就基本定位到和redux devtool有关系,但是不知道关系在哪,这个时候可以直接去github上寻找第一手资料,这样可以少走很多弯路。
3,特别复杂的问题,可以大事化小,小事化了,不断的尝试不断的缩小范围