我是Ramda的新手,只是想绕过它。所以这是我想用函数式重写的函数:
const makeReducer = (state, action) => {
if (action.type === LOG_OUT) {
return rootReducer(undefined, action)
}
return rootReducer(state, action)
}
以下是我的最终结果:
const isAction = type => R.compose(R.equals(type), R.prop('type'))
const makeReducer = (state, action) => {
const isLogOut = isAction(LOG_OUT)
return R.ifElse(isLogOut, rootReducer(undefined, action), rootReducer(state, action))(action)
}
我认为这是完全错误的,因为action
和rootReducer
有几个重复
答案 0 :(得分:1)
实际上我没有理由重构您的代码:您没有改变输入,而是使用if
来有条件地返回输出。
关于rootReducer(undefined, action)
,我相信您应该使用参数解构:
const rootReducer = ({ state, action } = {}} => {
// Stuff here
}
也就是说,您可以提供state
或action
,或同时提供两者:
const makeReducer = ({ state, action }) => {
if (action.type === LOG_OUT) {
return rootReducer({ action })
}
return rootReducer({ state, action })
}
另外,考虑使用terniary来解决简单的案例:
const makeReducer = ({ state, action }) =>
rootReducer( action.type === LOG_OUT ? { action } : { state, action } )
最后,可能还有另一种使用标记和和折叠的方法。由于我不使用 React 和/或 Redux ,我不知道你是否可以采用这种方法,但我相信你发现这个仍然很有趣替代解决方案:
const tag = Symbol ( 'tag' )
// TaggedSum
const Action = {
logout: value => ( { [tag]: 'logout', value } ),
login: value => ( { [tag]: 'login', value } )
}
const foldAction = matches => action => {
const actionTag = action[ tag ]
const match = matches [ actionTag ]
return match ( action.value )
}
const state = { x: 1 }
const LOG_IN = 1
const LOG_OUT = 2
const logout = Action.logout ( { action: LOG_OUT, state } )
const login = Action.login ( { action: LOG_IN, state } )
const rootReducer = args => console.log ( args )
// Pattern matching
const matchAction = {
logout: ( { state } ) => rootReducer( { state } ),
login: rootReducer
}
const foldAction_ = foldAction( matchAction )
foldAction_ ( logout )
foldAction_ ( login )
答案 1 :(得分:1)
你可以很容易地摆脱重复:
const makeReducer = (state, action) =>
rootReducer((action.type === LOG_OUT ? undefined : state), action)
这实际上既不是原作也不是功能。但它确实具有减少重复,并且只处理表达式而非处理语句的优点,这有时是功能技术的关注点。
但有一种方法显然不具备功能性。您的代码中有一个自由变量:LOG_OUT
。我从ALL_CAPS猜测这是一个常数。但功能并不知道。所以这个功能实际上并不是透明的。在具有相同参数的调用之间,有人可能会更改LOG_OUT
的值,您可能会得到不同的结果。
这使得该功能更难以测试。 (你不能只为它提供必要的参数;你还必须在范围内具有正确的LOG_OUT
值。)这使得它更难以推理。
没有此问题的替代方案是
const makeReducer = (state, action, types) =>
rootReducer((action.type === types.LOG_OUT ? undefined : state), action)
答案 2 :(得分:0)
如果要为代码使用无点样式语法,可以执行以下操作:
const initialState = {
text: 'initial text'
}
const rootReducer = R.curry((state, action) => {
// setting initial state could be improved
state = state || initialState
// your root reducer logic here
return state;
})
// R.last is here to grab the action in [state, action]
const isAction = type => R.compose(R.equals(type), R.prop('type'), R.last)
// first makes (state, action) into [state, action]
// before running R.cond
const makeReducer = R.compose(R.cond([
[isAction('LOG_OUT'), R.compose(rootReducer(undefined), R.last)],
// "default" action
[R.T, R.apply(rootReducer)]
]), R.pair)
const loggedOutState = makeReducer(
{ text: 'latest text'},
{ type: 'LOG_OUT'}
)
console.log(loggedOutState)
// => { text: 'initial text' }
const nextState = makeReducer(
{ text: 'latest text'},
{ type: 'ANY_ACTION'}
)
console.log(nextState)
// => { text: 'latest text' }

<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
&#13;
这个解决方案的优点是,您可以轻松扩展makeReducer
以处理更多操作(因为它使用R.cond
- 这就像一个switch语句)。