2015-11-02 16 views
9

Desidero scrivere un componente Form in grado di esportare un metodo per convalidarne i figli. Sfortunatamente un Modulo non "vede" alcun metodo sui suoi figli.Metodi di chiamata sui componenti figlio React

ecco come lo definisco un potenziale figli della Forma:

var Input = React.createClass({ 
    validate: function() { 
    ... 
    }, 
}); 

Ed ecco come lo definisco classe Form:

var Form = React.createClass({ 
    isValid: function() { 
    var valid = true; 
    this.props.children.forEach(function(component) { 
     // --> This iterates over all children that I pass 
     if (typeof component.validate === 'function') { 
     // --> code never reaches this point 
     component.validate(); 
     valid = valid && component.isValid(); 
     } 
    }); 
    return valid; 
    } 
}); 

ho notato che posso chiamare un metodo su un componente figlio usando refs, ma non posso chiamare un metodo tramite props.children.

C'è un motivo per questo comportamento di React?

Come posso risolvere questo?

risposta

13

Il motivo tecnico è che nel momento in cui si tenta di accedere al componente figlio, non esistono ancora realmente (nel DOM). Non sono ancora stati montati. Sono stati passati al componente <Form> come prop o metodo del costruttore come risposta classe. (da cui la classe nome in React.createClass()).

Come si fa notare, questo può essere aggirato utilizzando i riferimenti, ma non lo consiglierei. In molti casi, i ref tendono a essere scorciatoie per qualcosa a cui reagire non era destinato, e quindi dovrebbero essere evitati.

È probabile che, in base alla progettazione, la reazione impedisca ai genitori di accedere ai metodi di un bambino. Non dovrebbero. I metodi del bambino dovrebbero essere nel bambino se sono privati ​​del bambino: fanno qualcosa all'interno del bambino che non dovrebbe essere comunicato direttamente al genitore. Se così fosse, allora la manipolazione avrebbe dovuto essere fatta all'interno del genitore. Perché il genitore ha almeno tutte le informazioni e i dati del bambino.

Ora, nel tuo caso, immagino che ogni componente di input (figlio) abbia un qualche tipo di metodo di convalida specifico, che controlli il valore di input e, in base al risultato, restituisca un messaggio di errore. Diciamo un contorno rosso attorno ai campi errati.

Nel modo reagire, ciò potrebbe essere ottenuto come segue:

  • componente <Form> ha stato, che comprende un booleano runValidation.
  • non appena runValidation è impostato su true, all'interno di una risposta setState({ runValidation: true }); viene eseguito automaticamente il rendering di tutti i bambini.
  • se si include runValidation come sostegno per tutti i bambini.
  • poi ogni bambino può controllare all'interno della loro funzione render() con qualcosa di simile if (this.props.runValidation) { this.validate() }
  • che eseguirà la funzione validate() nel bambino
  • la funzione di convalida può anche utilizzare lo stato del bambino (lo stato non viene modificato quando i nuovi oggetti di scena sono disponibili in), e usa quello per il messaggio di convalida (es. "aggiungi simboli più complicati alla tua password")

Ora, ciò che non risolve ancora, è che potresti voler fare un controllo a livello di modulo dopo tutto i bambini si sono convalidati: es quando tutti i bambini sono OK, invia il modulo.

Per risolvere ciò, è possibile applicare la scorciatoia di riferimento al controllo finale e inviare. E implementa un metodo nel tuo <Form> all'interno di una funzione componentDidUpdate(), per verificare se ogni bambino è OK (ad esempio ha un bordo verde) E se l'invio è cliccato, e quindi invia. Ma come regola generale, consiglio vivamente di non usare i ref.

Per la convalida forma finale, un approccio migliore è:

  • aggiungere una variabile non statale all'interno della vostra <Form> che detiene booleani per ogni bambino. NB, deve essere non-stato, per impedire ai bambini di attivare un nuovo ciclo di rendering.
  • passare una funzione validateForm come un puntello (callback) per ogni bambino.
  • all'interno di validate() in ogni bambino, chiamare this.props.validateForm(someChildID) che aggiorna il valore booleano corrispondente nella variabile nel modulo.
  • alla fine della funzione validateForm nel modulo, controllare se tutti i valori booleani sono veri e, in tal caso, inviare il modulo (o modificare lo stato del modulo o qualsiasi altra cosa).

Per una soluzione ancora più lunga (e molto più complicata) per formare la convalida in risposta (con flusso) è possibile controllare this article.

+0

Perché una variabile per la convalida deve essere una variabile non di stato? –

+2

Perché non si desidera eseguire nuovamente il rendering del modulo quando ogni bambino riporta "Ok" o "non Ok", ovvero cosa succederebbe se lo si inserisse nello stato modulo. Si desidera solo avere lo stato per il modulo completo e modificare lo stato/ri-rendering solo se tutti i bambini sono OK. – wintvelt

0

Non sono sicuro se mi manca qualcosa, ma dopo aver provato quello che ha suggerito @wintvelt mi sono imbattuto in un problema ogni volta che ho chiamato il metodo runValidation all'interno del metodo rendering di reagire, dal momento che nel mio caso runValidation modifica lo stato da chiamando setState, innescando così il metodo render che ovviamente è una cattiva pratica dato che il metodo render deve essere puro, e se metto il runValidation in willReceiveProps non sarà chiamato la prima volta perché la condizione if non è ancora vera (questo la condizione viene modificata nel componente principale utilizzando setState, ma nella prima chiamata di willReceiveProps è ancora falso).

+0

Probabilmente è meglio aprire un'altra domanda su questo argomento. Ma come spiegazione: nella mia risposta, il genitore (Form) possiede un flag booleano ('runValidation'), che determina se deve essere eseguito o meno il metodo' validate() 'del bambino. Questo metodo all'interno del bambino fa parte del rendering del bambino e non dovrebbe (o deve) modificare lo stato del bambino. Il metodo 'validate()' serve solo a determinare se è necessario aggiornare qualsiasi messaggio di convalida visualizzato. – wintvelt

Problemi correlati