你怎么写ramda的条件?

时间:2018-05-19 06:34:47

标签: redux functional-programming ramda.js

我是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)
}

我认为这是完全错误的,因为actionrootReducer有几个重复

3 个答案:

答案 0 :(得分:1)

实际上我没有理由重构您的代码:您没有改变输入,而是使用if来有条件地返回输出。

关于rootReducer(undefined, action),我相信您应该使用参数解构:

const rootReducer = ({ state, action } = {}} => {
   // Stuff here
}

也就是说,您可以提供stateaction,或同时提供两者:

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;
&#13;
&#13;

这个解决方案的优点是,您可以轻松扩展makeReducer以处理更多操作(因为它使用R.cond - 这就像一个switch语句)。