在Redux Reducer中使用Ramda.evolve方法失效的问题排查
问题原因与解决方案
你遇到的问题核心是对R.evolve的用法理解有误——R.evolve的第一个参数需要是一个「属性到转换函数」的映射对象,而不是直接传入新值。
为什么当前代码不工作?
R.evolve的设计逻辑是:遍历你传入的映射对象,对原状态中对应的每个属性,用映射对象里的函数去转换它的旧值,最终返回新状态。而你现在直接把action.mode、action.directory这些具体值传给了映射对象的属性,这相当于给每个属性分配了一个「非函数」的值,Ramda无法执行转换逻辑,自然就返回了原状态。
修正后的代码
要实现用action里的新值替换原状态的mode和directory,你需要用R.always函数来生成一个返回固定值的转换函数(或者直接用箭头函数() => action.mode也可以):
const handlers = { [SET_MODE]: (state, action) => R.evolve( { mode: R.always(action.mode), directory: R.always(action.directory) }, state ), [TOGGLE_LOADER]: (state, action) => R.assoc("loading", action.loading, state) };
更简洁的替代方案
如果只是简单地替换状态中的几个属性,其实用R.merge会更直观,不需要绕evolve:
const handlers = { [SET_MODE]: (state, action) => R.merge(state, { mode: action.mode, directory: action.directory }), [TOGGLE_LOADER]: (state, action) => R.assoc("loading", action.loading, state) };
或者用R.pick提取action中需要的属性再合并,避免意外引入其他多余属性:
const handlers = { [SET_MODE]: (state, action) => R.merge(state, R.pick(['mode', 'directory'], action)), [TOGGLE_LOADER]: (state, action) => R.assoc("loading", action.loading, state) };
补充说明
如果你确实需要使用R.evolve(比如某些属性需要基于旧值做计算),那一定要确保映射对象的每个值都是函数。比如如果mode需要在旧值基础上修改,你可以写:
{ mode: oldMode => `${oldMode}-${action.suffix}` }
内容的提问来源于stack exchange,提问作者rvpanoz
相关产品推荐
相关产品推荐

