在FieldArray组件中使用Redux Form Fields组件

时间:2016-09-27 17:01:49

标签: redux-form

我有一个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' ] )。

我试图以通用方式获取valuevalueIsRegex个对象,以支持我在上面提到的任何情况。

现在我已经创建了一个函数,我使用RegEx来确定字段。但我想知道是否有人知道更好的方法来做到这一点(也许有一个Redux Form util可能是我在阅读文档时遗漏的)。

2 个答案:

答案 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">&#xE5CD;</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)));
}

另见this github issue

相关问题