2016-09-27 10 views
0

Ich habe eine Fields Komponente, die ich manchmal selbst und manchmal von innerhalb einer FieldArray Komponente zu verwenden versuche. Ich habe unten einen Ausschnitt mit einem vereinfachten Modell hinzugefügt.Verwendung von Redux Form Fields Komponente in einer FieldArray-Komponente

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')); 

Wenn ich die Fields Komponente selbst zu verwenden, das fields Argument von innen renderSharedComponent hat die folgende Form:

{ 
    value: { input: {...}, meta: {...} }, 
    valueIsRegex: { input: {...}, meta: {...} }, 
    names: [ 'value' , 'valueIsRegex' ] 
} 

Wenn ich die Fields Komponente innerhalb einer FieldArray Komponente, die fields Argument von innen renderSharedComponent hat die folgende Form:

{ 
    hashes: [ 
     { 
     value: { input: {...}, meta: {...} }, 
     valueIsRegex: { input: {...}, meta: {...} } 
     } 
    ], 
    names: [ 'hashes[0].value' , 'hashes[0].valueIsRegex' ] 
} 

Wenn ich die Fields Komponente in einer FieldArray Komponente mit einem anderen Namen (sagen wir paths) verwenden werde, ändert sich die Eigenschaft names entsprechend (z. B. names: [ 'paths[0].value' , 'paths[0].valueIsRegex' ]).

Ich versuche, die value und valueIsRegex Objekte in einer generischen Weise zu erhalten, die jeden der oben dargestellten Fälle unterstützen wird.

Jetzt habe ich eine Funktion erstellt, wo ich eine RegEx verwenden, um die Felder zu bestimmen. Aber ich frage mich, ob irgendjemand einen besseren Weg kennt, dies zu tun (vielleicht gibt es ein Redux-Formular, das ich vielleicht beim Lesen der Dokumentation übersehen habe).

Antwort

1

mit dem gleichen Problem. Es kann sein, dass der idiomatische Weg ist, die formValueSelectorfunction zu verwenden. Aber auf diese Weise ist es etwas mehr gebrannt, da Sie den Selektor (so weit ich es verstanden habe) den ganzen Weg durch das Formular passieren müssen. Persönlich habe ich auch die Regexp-basierte Funktion. Hier ist sie:

/** 
 
* 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> 
 
    ); 
 
};

0

redux-Form eine versteckte Nutzenfunktion hat, die hier nützlich ist, aber ich weiß nicht, ob Sie es Verfügbarkeit in zukünftigen Versionen verlassen können:

import structure from "redux-form/lib/structure/plain"; 

function RenderRow({ names, ...props }) { 
    const fields = {}; 
    names.forEach(n => (fields[n] = structure.getIn(props, n))); 
} 

Siehe auch this github issue

Verwandte Themen