我有一个Fields
组件,我有时会单独使用,有时也会从FieldArray
组件中使用。我在下面添加了一个简化模型的片段。
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { reduxForm, Fields, FieldArray, reducer as formReducer } from 'redux-form';
const reducers = {
form: formReducer
};
const reducer = combineReducers(reducers);
const store = createStore(reducer);
const renderSharedComponent = (fields) => {
console.log(fields);
return (<div>Shared Component</div>);
};
const renderHashes = ({ fields }) => (
<div>
{
fields.map((field) => (
<Fields
key={ field }
names={ [`${field}.value`, `${field}.valueIsRegex`] }
component={ renderSharedComponent }
/>
))
}
</div>
);
const ReactComponent = () => (
<div>
<FieldArray
name="hashes"
component={ renderHashes }
/>
<Fields
names={ ['value', 'valueIsRegex'] }
component={ renderSharedComponent }
/>
</div>
);
const ReduxForm = reduxForm({
form: 'default',
initialValues: {
hashes: [{}]
}
})(ReactComponent);
ReactDOM.render((
<div>
<Provider store={ store }>
<ReduxForm />
</Provider>
</div>
), document.getElementById('content'));
当我单独使用Fields
组件时,fields
内的renderSharedComponent
参数的格式如下:
{
value: { input: {...}, meta: {...} },
valueIsRegex: { input: {...}, meta: {...} },
names: [ 'value' , 'valueIsRegex' ]
}
当我在Fields
组件中使用FieldArray
组件时,fields
内的renderSharedComponent
参数的格式如下:
{
hashes: [
{
value: { input: {...}, meta: {...} },
valueIsRegex: { input: {...}, meta: {...} }
}
],
names: [ 'hashes[0].value' , 'hashes[0].valueIsRegex' ]
}
如果我将使用Fields
组件中的FieldArray
组件使用不同的名称(让我们说paths
),则names属性会相应更改(例如names: [ 'paths[0].value' , 'paths[0].valueIsRegex' ]
)。
我试图以通用方式获取value
和valueIsRegex
个对象,以支持我在上面提到的任何情况。
现在我已经创建了一个函数,我使用RegEx来确定字段。但我想知道是否有人知道更好的方法来做到这一点(也许有一个Redux Form util可能是我在阅读文档时遗漏的)。
答案 0 :(得分:1)
遇到同样的问题。可能是惯用的方式是使用formValueSelector
function。但是这样的方式更多的是样板,因为你必须通过表单传递选择器(据我所知)。
我个人也做了基于正则表达式的函数。这是:
/**
* Converts path expression string to array
* @param {string} pathExpr path string like "bindings[0][2].labels[0].title"
* @param {Array<string|int>} array path like ['bindings', 0, 2, 'labels', 0, 'title']
*/
function breakPath(pathExpr) {
return pathExpr
.split(/\]\.|\]\[|\[|\]|\./)
.filter(x => x.length > 0)
.map(x => isNaN(parseInt(x)) ? x : parseInt(x));
}
/**
* Executes path expression on the object
* @param {string} pathExpr – path string like "bindings[0][2].labels[0].title"
* @param {Object|Array} obj - object or array value
* @return {mixed} a value lying in expression path
* @example
* ```
* execPath('books[0].title', {books: [{title: 'foo'}]})
* // yields
* 'foo'
* ```
*/
function execPath(pathExpr, obj) {
const path = breakPath(pathExpr);
if (path.length < 1) {
return obj;
}
return path.reduce(function(obj, pathPart) {
return obj[pathPart];
}, obj);
}
/**
* A generic GroupLabelField that relies on valueBasePath
*/
const GroupLabelField = (props) => {
const groupData = execPath(props.valueBasePath, props);
return (
<div className={`label__content label__content_icon_${groupData.objectType.input.value}`}>
<span className="label__remove"
onClick={(e) => { props.handleRemove(); e.stopPropagation(); }}
>
<i className="material-icons material-icons_12 material-icons_top"></i>
</span>
<span className="label__text">{groupData.title.input.value}</span>
</div>
);
};
答案 1 :(得分:1)
redux-form有一个隐藏的实用函数,在这里很有用,但我不知道你是否可以在将来的版本中依赖它的可用性:
import structure from "redux-form/lib/structure/plain";
function RenderRow({ names, ...props }) {
const fields = {};
names.forEach(n => (fields[n] = structure.getIn(props, n)));
}