在 Ramda 中思考
Thinking in Ramda
我知道 Ramda 有很多有用的功能,但我不知道,如何组合它比这个更好。有人可以做得更好吗?
PS。参考一下 Ramda 中的 think 就好了。
// @flow
/**
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'input-id', formId: 'form-id', value: ''}
]
}
*/
import { propEq, find, update, compose, assoc, assocPath, findIndex } from 'ramda';
export const setInputValueInState = (
inputId: string,
value: string,
state: FormsState,
): FormsState => {
const input = getInputById(inputId, state);
const inputWithNewValue = assoc('value', value, input);
const inputIndex = findIndex(propEq('inputId', inputId))(state.inputs);
return assocPath(['inputs', inputIndex], inputWithNewValue, state);
};
有很多方法可以解决这个问题。通过巧妙地使用 useWith
or converge
,您可能可以创建现有函数的无点版本。不过,我不认为它最终会变得特别可读,所以我会寻找其他技术。
一种可能是使用lenses
。大多数关于镜头的文章都适用于 Haskell 或其他语言。但我在 A. Sharif, Drew Tipson, and Vladimir Gorej
的 Javascript 中找到了一些
Ramda 有几个内置镜头创建功能,lensProp
, lensPath
, and lensIndex
, as well as functions like view
, set
, and over
可以使用镜头。但是创建您自己的也很容易,例如下面的 inputIdLens
。
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'i-1', formId: 'foo-12', value: '123'},
{inputId: 'i-2', formId: 'bar-34', value: '234'},
{inputId: 'i-3', formId: 'baz-56', value: '345'},
{inputId: 'i-4', formId: 'qux-78', value: '456'},
{inputId: 'i-5', formId: 'corge-90', value: '567'}
]
}
const {lens, find, propEq, update, findIndex, set, compose, lensProp} = R
const inputIdLens = (inputId) => lens(
(s) => find(propEq('inputId', inputId), s),
(a, s) => update(findIndex(propEq('inputId', inputId), s), a, s)
)
const setInputValueInState = (inputId, val, state) =>
set(compose(lensProp('inputs'), inputIdLens(inputId), lensProp('value')), val, state)
console.log(setInputValueInState('i-2', 'foobar', state))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
尽管 Scott 的回答感觉更实用,但我发现这种方法更易于编写和理解。我更喜欢 evolve
而不是镜头,IMO 感觉更自然。
import { curry, evolve, adjust, findIndex, propEq, assoc } from 'ramda';
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'i-1', formId: 'form-1', value: '123'},
{inputId: 'i-2', formId: 'form-2', value: '234'},
]
}
const setInputValueInState = curry((inputId, value, obj) => evolve({
inputs: adjust(
findIndex(propEq('inputId', inputId), obj.inputs),
assoc('value', value),
),
}, obj));
setInputValueInState('i-2', 'foobar', state);
我知道 Ramda 有很多有用的功能,但我不知道,如何组合它比这个更好。有人可以做得更好吗? PS。参考一下 Ramda 中的 think 就好了。
// @flow
/**
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'input-id', formId: 'form-id', value: ''}
]
}
*/
import { propEq, find, update, compose, assoc, assocPath, findIndex } from 'ramda';
export const setInputValueInState = (
inputId: string,
value: string,
state: FormsState,
): FormsState => {
const input = getInputById(inputId, state);
const inputWithNewValue = assoc('value', value, input);
const inputIndex = findIndex(propEq('inputId', inputId))(state.inputs);
return assocPath(['inputs', inputIndex], inputWithNewValue, state);
};
有很多方法可以解决这个问题。通过巧妙地使用 useWith
or converge
,您可能可以创建现有函数的无点版本。不过,我不认为它最终会变得特别可读,所以我会寻找其他技术。
一种可能是使用lenses
。大多数关于镜头的文章都适用于 Haskell 或其他语言。但我在 A. Sharif, Drew Tipson, and Vladimir Gorej
Ramda 有几个内置镜头创建功能,lensProp
, lensPath
, and lensIndex
, as well as functions like view
, set
, and over
可以使用镜头。但是创建您自己的也很容易,例如下面的 inputIdLens
。
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'i-1', formId: 'foo-12', value: '123'},
{inputId: 'i-2', formId: 'bar-34', value: '234'},
{inputId: 'i-3', formId: 'baz-56', value: '345'},
{inputId: 'i-4', formId: 'qux-78', value: '456'},
{inputId: 'i-5', formId: 'corge-90', value: '567'}
]
}
const {lens, find, propEq, update, findIndex, set, compose, lensProp} = R
const inputIdLens = (inputId) => lens(
(s) => find(propEq('inputId', inputId), s),
(a, s) => update(findIndex(propEq('inputId', inputId), s), a, s)
)
const setInputValueInState = (inputId, val, state) =>
set(compose(lensProp('inputs'), inputIdLens(inputId), lensProp('value')), val, state)
console.log(setInputValueInState('i-2', 'foobar', state))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
尽管 Scott 的回答感觉更实用,但我发现这种方法更易于编写和理解。我更喜欢 evolve
而不是镜头,IMO 感觉更自然。
import { curry, evolve, adjust, findIndex, propEq, assoc } from 'ramda';
const state = {
forms: [
{id: 'form-id'}
],
inputs: [
{inputId: 'i-1', formId: 'form-1', value: '123'},
{inputId: 'i-2', formId: 'form-2', value: '234'},
]
}
const setInputValueInState = curry((inputId, value, obj) => evolve({
inputs: adjust(
findIndex(propEq('inputId', inputId), obj.inputs),
assoc('value', value),
),
}, obj));
setInputValueInState('i-2', 'foobar', state);