如何在给定的对象结构中使用Ramda执行嵌套更新? [英] How to perform a nested update using Ramda in the given object structure?

查看:73
本文介绍了如何在给定的对象结构中使用Ramda执行嵌套更新?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设遵循对象,如何使用Ramda在给定应用程序,条件ID和数据的条件下执行嵌套更新?

Assuming the follow object how is it possible to use Ramda to perform a nested update in a criteria given an application, criteria ID and data?

const application = {
  id: 'a1',
  features: [
    {
      id: 'f1',
      criterias: [
        { id: 'c1' }
      ]
    },
    {
      id: 'f2',
      criterias: [
        { id: 'c2' },
        { id: 'c3' }
      ]
    }
  ]
}

函数看起来像这样:

const updateCriteria = (application, criteriaId, data) => // magic...

updateCriteria(application, 'c2', { name: 'foo' })

// output: {
//  id: 'a1',
//  features: [
//    {
//      id: 'f1',
//      criterias: [
//        { id: 'c1' }
//      ]
//    },
//    {
//      id: 'f2',
//      criterias: [
//        { id: 'c2', name: 'foo' },
//        { id: 'c3' }
//      ]
//    }
//  ]
// }

推荐答案

为此可能最好的选择是透镜. Ramda具有通用的 lens 函数,以及针对对象属性的特定函数( lensProp ),以获取数组索引( lensPath ),但其中不包含通过ID在数组中查找匹配值的值.不过,打造我们自己并不难.

Lenses are probably your best bet for this. Ramda has a generic lens function, and specific ones for an object property (lensProp), for an array index(lensIndex), and for a deeper path(lensPath), but it does not include one to find a matching value in an array by id. It's not hard to make our own, though.

通过将两个函数传递给lens来制成镜头:一个获取对象并返回相应值的吸气剂,以及获取新值和对象并返回对象的更新版本的塞特透镜.

A lens is made by passing two functions to lens: a getter which takes the object and returns the corresponding value, and a setter which takes the new value and the object and returns an updated version of the object.

在这里,我们编写lensMatch,该表达式在给定属性名称与提供的值匹配的数组中查找或设置值.而lensId只需将'id'传递给lensMatch即可返回一个函数,该函数将获取id值并返回镜头.

Here we write lensMatch which find or sets the value in the array where a given property name matches the supplied value. And lensId simply passes 'id' to lensMatch to get back a function which will take an id value and return a lens.

使用任何镜头,我们都有 view

Using any lens, we have the view, set, and over functions which, respectively, get, set, and update the value.

我们可以这样使用idLens:

const data = [{id: 'a'}, {id: 'b'}, {id: 'c'}]

view (idLens ('b'), data) 
  //=> {id: 'b'}
set  (idLens ('b'), 'foo', data) 
  //=> [ {id: 'a'}, 'foo', {id: 'c'} ]
over (idLens ('b'), merge ({name: 'foo'}), data)
  //=> [ {id: 'a'}, {id: 'b', name: 'foo}, {id: 'c'} ]

因此,对于您的问题,我们可以这样写:

So for your problem, we could write something like this:

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 lensId = lensMatch ('id')

const updateCriteria = (featureId, criteriaId, data, application) => over 
  ( compose 
      ( lensProp ('features')
      , lensId (featureId) 
      , lensProp ('criterias') 
      , lensId (criteriaId)
      )
    , merge (data)
    , application
    )

const application = {id: 'a1', features: [{id: 'f1', criterias: [{ id: 'c1' }]}, {id: 'f2', criterias: [{ id: 'c2' }, { id: 'c3' }]}]}

const newApp = updateCriteria ('f2', 'c2', {name: 'foo'}, application)

console.log(newApp)

<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
<script>
const {lens, find, propEq, findIndex, update, length, view, set, over, compose, lensProp, merge} = R
</script>

但是前提是您知道featureId.如果您需要同时找到featureId和带有内部ID的嵌套对象,则可以为此编写一个更复杂的镜头,但重量会更大.

But this presupposes that you know the featureId. If you need to find both the featureId and the nested object with your internal id, you could write a more complex lens for that, but it will be much more heavyweight.

一个小注释:条件"已经是复数形式,因此条件"是奇数.单数是标准".

A minor note: 'criteria' is already plural, so 'criterias' is odd. The singular is 'criterion'.

这篇关于如何在给定的对象结构中使用Ramda执行嵌套更新?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆