問題

我的團隊和我每天強烈地整合FP和react-hooks模式,雖然有時我們正在努力如何與純函式一起管理鉤子.最近,我們遇到了很多情況,其中鉤子“回撥”必須位於compose或另一個變壓器中的某個地方 – 在這種情況下,它是evolve函式,例如:

 const getDefinedActions = R.filter(
      R.both(isActionDefined, R.ifElse(hasAfterConfirm, isAfterConfirmDefined, R.T))
    )
    
const translateTitles = R.map(
  R.evolve({
    title: title => useTranslate()(title)
  })
)

export const useActions = R.compose(
  translateTitles,
  getDefinedActions
) 

在上面的示例中,我們想過濾基於某些謂詞新增翻譯的操作,這需要使用useTranslate鉤子.不幸的是,我們不能只在那裡寫useTranslate(),因為在安裝React元件後必須初始化鉤子.到目前為止在這些情況下做了什麼:

  • 建立鉤子函式“在飛行中”,並將其傳遞給另一個ramda的函式.例如{ const translate = useTranslate(); return R.compose(..., translate, ...) } – 我們不喜歡這個aproach,因為我們在這樣做時無法納入無點樣式;/

  • 另一種方法是像我在上面的片段中寫的那樣在匿名函式中呼叫鉤子. – 雖然我們不必編寫整個函式塊並宣告一個額外的變數,我們也不喜歡這種方法,因為我們感覺像所有時候我們都必須冗餘寫傳遞的引數:arg => hook()(arg)

FP中是否有任何一般方法來處理這種問題,我們必須注入函式,這必須懶惰地評估,然後根據這個結果我們可以進行其他計算?也許Ramda本身具有函式,這有助於注入特定行為,所以我們可以像這樣使用它:

 R.evolve({
  title: R.useWith(useTranslate, R.identity) // arg => useTranslate()(R.identity(arg))
})
 

PS.我知道在ramda中有一個名為useWith的函式,但它以不同的方式工作;/

任何幫助將非常感激!

  最佳答案

我不確定我完全理解你的問題.你是否只是尋找一種方法來進行useTranslate的初始化只有一次?如果是這樣,那麼我不認為ramda有任何內建的東西,但編寫這樣的東西會很容易

 const dethunk = (fn) => {
  let initialized = null;
  return (...args) => (initialized || (initialized = fn())) (...args)
}
 

然後寫一些類似的東西。

 const translateTitles = map (evolve ({title: dethunk(useTranslate) }))
 

如果您想將引數傳遞給初始化,您可以將其更改為

 const dethunk = (fn, ...initialArgs) => {
  let initialized = null;
  return (...args) => (initialized || (initialized = fn(...initialArgs))) (...args)
}

const foo = (a, b) => {
  console.log(`Initializing with '${a}' and '${b}'`)
  return (c) => `foo('${a}', '${b}', ${c})`
}

const bar = dethunk(foo, 'x', 'y')

console.log('Have not initialized yet');

console .log (bar (1))
console .log (bar (2))
console .log (bar (3)) 

這是你需要的嗎?