2015-07-01 12 views
6

C'è un modo per avere più convalide su un singolo puntello usando React.PropTypes. in particolare desidera miscelare una convalida personalizzata e una convalida delle scorte.Convalida multipla su Propiy React

Ho due oggetti di scena, un oggetto options e una stringa value. Voglio verificare che props.value sia una stringa ma anche una chiave sull'oggetto. utilizzando CoffeeScript questo appare come:

propTypes: 
    options: React.PropTypes.Object.isRequired 
    value: (props, propName, componentName) -> 
    unless props[propName] of props.options 
     new Error('my custom message') 

questa grande opera, ma voglio anche al fine di garantire che il mio valore è un tipo stringa. Sono sicuro di poter inserire manualmente quella convalida nella funzione personalizzata senza problemi, ma idealmente, mi piacerebbe solo usare React.PropTypes.string.isRequired. Ho provato a metterlo nella funzione personalizzata e ad eseguirlo ma non ha funzionato. quanto segue non funzionavano:

value: React.PropTypes.string.isRequired && (props, propName, componentName) -> 
    unless props[propName] of props.options 
     new Error('my custom message') 

c'è un modo per ottenere questo lavoro utilizzando reagisce costruito nel validatore, o è riscriverlo nella mia funzione l'unica opzione?

risposta

2

Dalla pagina Reusable Components nella documentazione:

You can also specify a custom validator. It should return an Error 
// object if the validation fails. Don't `console.warn` or throw, as this 
// won't work inside `oneOfType`. 
customProp: function(props, propName, componentName) { 
    if (!/matchme/.test(props[propName])) { 
    return new Error('Validation failed!'); 
    } 
} 

Quindi un PropType restituisce nulla o di un oggetto di errore. Possiamo scrivere una funzione "tutto" che prende due propTypes e unisce il risultato.

const allPropTypes = (...types) => (...args) => { 
    const errors = types.map((type) => type(...args)).filter(Boolean); 

    // no errors? cool! 
    if (errors.length === 0) return; 

    // collect the messages and join them together 
    const message = errors.map((e) => e.message).join('\n'); 
    return new Error(message); 
}; 

Quindi è possibile utilizzare questo far valere nei confronti multipli propTypes.

propTypes = { 
    foo: allPropTypes(
    PropTypes.string.isRequired, 
    (props, propName, componentName) => props.options && props.options[props[propName]] 
     ? undefined 
     : new Error(
      `${componentName}: expected prop ${propName}="${prop[propName]}"` 
      + `to be a key of prop "options" ` 
      + `(one of ${Object.keys(props.options).join(', ')})` 
     ) 
) 
} 

Nota: tutto questo non è testato, ma errori di sintassi! Puoi compilarlo in es3 con babel, o convertirlo in CS a mano.

+0

Sono consapevole di poter continuare ad aggiungere le cose alla convalida personalizzata. potrebbe probabilmente andare avanti con 'return new Error ('msg') a meno che typeof props [propName] == 'string'', ma sto chiedendo se esiste un modo più formale che fornisce la reazione (cioè essere ancora in grado di usa 'React.PropTypes.string.isRequired') perché è molto più evidente su ciò che sta succedendo su – PhilVarg

+0

@PhilVarg è necessario creare il proprio proptype. Nessuno dei propTypes incorporati esegue alcun controllo incrociato per quanto ne so. Puoi metterlo in un modulo da qualche parte e importarlo con un bel nome, e persino avere la parte 'options' dinamica, ad es. 'pippo: isKeyOfProp ('opzioni')'. – FakeRainBrigand

0

Se si segue il collegamento this, Ian Thomas spiega l'uso di un metodo createChainableTypeChecker che è in risposta ma non viene esportato come parte del modulo propTypes. L'articolo ha una chiara spiegazione di come è possibile utilizzare lo stesso codice per convalidare chiamate di convalida:

function createChainableTypeChecker(validate) { 
    function checkType(isRequired, props, propName, componentName, location) { 
    componentName = componentName || ANONYMOUS; 
    if (props[propName] == null) { 
     var locationName = ReactPropTypeLocationNames[location]; 
     if (isRequired) { 
     return new Error(
      ("Required " + locationName + " `" + propName + "` was not specified in ") + 
      ("`" + componentName + "`.") 
     ); 
     } 
     return null; 
    } else { 
     return validate(props, propName, componentName, location); 
    } 
    } 

    var chainedCheckType = checkType.bind(null, false); 
    chainedCheckType.isRequired = checkType.bind(null, true); 

    return chainedCheckType; 
} 
+0

Dove posso ottenere ReactPropTypeLocationNames? – Shanimal