如何在给定的对象结构中使用Ramda执行嵌套更新? [英] How to perform a nested update using Ramda in the given object structure?
问题描述
假设遵循对象,如何使用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
, over
函数,分别获取,设置和更新值.
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屋!