基于对象中某些值的 Ramda 镜头

Ramda lenses based on a some value in object

社区,您好。我遇到了一个小问题。 我有这样一个数据结构

{
    "type": "Shoes",
    "gender": "female",
    "userInfo": {
        "whois": {
            "male": {
                "htt": 20.2,
                "referenceBrands": [{
                    "category": "Shoes",
                    "size": 40
                }]
            },
            "female": {
                "height": 191.0,
                "age": 20,
                "referenceBrands": [{
                    "category": "Shoes",
                    "size": 35.5
                }, {
                  "category": "Apparel",
                  "size": 50
                }]
            }
        },
    }
}

我想根据根中的 gendertype 更新参考品牌中的特定密钥。 基于此 (感谢 Scott Sauyet),我创建了类似的东西。但是如您所见,我已经对 gendercategory 进行了硬编码,使用组合和无点样式来更改此设置的最佳方法是什么?

const lensMatch = (propName) => (key) => lens( 
   find(
      propEq(propName, key)
   ), 
   (val, arr, idx = findIndex(propEq (propName, key), arr)) =>
         update(idx > -1 ? idx : length (arr), val, arr)
   )

const lensCategory = lensMatch('category')
const genderLens = lensProp('gender')
const lensReferenceBrand = lensProp('referenceBrands')

const updateSize = (prop, value) => over(
  compose(
    lensPath(['userInfo', 'whois']),
    lensProp('female'),
    lensReferenceBrand,
    lensCategory('Shoes'),
    lensProp(prop),
  ), always(value), data)

updateSize('size', 100)

Playground

我可能会这样写:

const lensMatch = (propName) => (key) => 
  lens
    ( find (propEq (propName, key))
    , (val, arr, idx = findIndex (propEq (propName, key), arr)) =>
        update(idx > -1 ? idx : length (arr), val, arr)
    )

const updateSize = (prop, value, gender, category, data) => 
  set 
    ( compose 
        ( lensPath (['userInfo', 'whois', gender, 'referenceBrands'])
        , lensMatch ('category') (category)
        , lensProp (prop)
        )
    , value
    , data
    )
  

const data = {type: "Shoes", gender: "female", userInfo: {whois: {male: {htt: 20.2, referenceBrands: [{category: "Shoes", size: 40}]}, female: {height: 191, age: 20, referenceBrands: [{category: "Shoes", size: 35.5}, {category: "Apparel", size: 50}]}}}};

console .log (
  updateSize ('size', 100, 'female', 'Shoes', data)
)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>const {lens, find, findIndex, propEq, update, length, set, compose, lensPath, lensProp} = R  </script>

请注意,我将 over 替换为 setover 是关于通过将函数应用于旧值来创建新值,set 只是将其设置为给定值。这意味着我也可以删除多余的 always

当然你也可以使用

    ( compose 
        ( lensPath (['userInfo', 'whois'])
        , lensProp (gender)
        , lensProp ('referenceBrands')
        , lensMatch ('category') (category)
        , lensProp (prop)
        )

甚至将 lensPath 分成两个 lensProp,但我看不出有什么理由。

这远非毫无意义。事实上,主函数有五个命名参数,比我通常习惯的多两个,比我喜欢的多四个。但它们似乎都是必要的。而且我只有在提高可读性时才选择无点。我怀疑无点解决方案会使情况变得更糟。

我不知道这个部分应用的版本是否有帮助,但将签名更改为

会很容易
const updateSize = (prop, value) => (gender, category) => (data) => ...
// ...
updateSize ('size', 100) ('female', 'Shoes') (data)

或类似的,或使用 R.curry