如何在给定的对象结构中使用 Ramda 执行嵌套更新?
How to perform a nested update using Ramda in the given object structure?
假设以下对象,如何使用 Ramda 在给定应用程序、条件 ID 和数据的条件中执行嵌套更新?
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
function, and specific ones for an object property (lensProp
), for an array index(lensIndex
), and for a deeper path(lensPath
),但它不包括通过 id 在数组中查找匹配值的方法。不过,我们自己制作并不难。
通过将两个函数传递给 lens
来制作镜头:一个 getter 获取对象和 returns 相应的值,以及一个 setter 获取新值和对象以及 return 对象的更新版本。
这里我们写 lensMatch
来查找或设置数组中的值,其中给定的 属性 名称与提供的值相匹配。 lensId
只是将 'id'
传递给 lensMatch
以取回一个函数,该函数将采用 id 值和 return 镜头。
使用任何镜头,我们都有 view
, set
, and over
函数,分别获取、设置和更新值。
我们可以这样使用 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'} ]
所以对于你的问题,我们可以这样写:
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 的嵌套对象,您可以为此编写一个更复杂的镜头,但它会更重量级。
小提示:'criteria' 已经是复数,所以 'criterias' 是单数。单数是'criterion'.
假设以下对象,如何使用 Ramda 在给定应用程序、条件 ID 和数据的条件中执行嵌套更新?
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
function, and specific ones for an object property (lensProp
), for an array index(lensIndex
), and for a deeper path(lensPath
),但它不包括通过 id 在数组中查找匹配值的方法。不过,我们自己制作并不难。
通过将两个函数传递给 lens
来制作镜头:一个 getter 获取对象和 returns 相应的值,以及一个 setter 获取新值和对象以及 return 对象的更新版本。
这里我们写 lensMatch
来查找或设置数组中的值,其中给定的 属性 名称与提供的值相匹配。 lensId
只是将 'id'
传递给 lensMatch
以取回一个函数,该函数将采用 id 值和 return 镜头。
使用任何镜头,我们都有 view
, set
, and over
函数,分别获取、设置和更新值。
我们可以这样使用 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'} ]
所以对于你的问题,我们可以这样写:
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 的嵌套对象,您可以为此编写一个更复杂的镜头,但它会更重量级。
小提示:'criteria' 已经是复数,所以 'criterias' 是单数。单数是'criterion'.