2014-06-16 14 views
20

Ich versuche zub zu integrieren offenbaren mit Form in reagieren Komponente. Bisher nächsten Code korrekt angezeigt modale Form:Wie man react.js schön zusammen mit zurb machen kann, offenbaren Modalform

ModalForm = React.createClass({ 
    handleSubmit: function(attrs) { 
    this.props.onSubmit(attrs); 
    return false; 
    }, 

    render: function(){ 
    return(
     <div> 
     <a href="#" data-reveal-id="formModal" className="button">Add new</a> 
     <div id="formModal" className="reveal-modal" data-reveal> 
      <h4>Add something new</h4> 
      <Form onSubmit={this.handleSubmit} /> 
      <a className="close-reveal-modal">&#215;</a> 
     </div> 
     </div> 
    ); 
    } 
}); 

Die Form Komponente ist ziemlich Standard:

Form = React.createClass({ 
    handleSubmit: function() { 
    var body = this.refs.body.getDOMNode().value.trim(); 
    if (!body) { 
     return false; 
    } 
    this.props.onSubmit({body: body}); 
    this.refs.body.getDOMNode().value = ''; 
    return false; 
    }, 
    render: function(){ 
    return(
     <form onSubmit={this.handleSubmit}> 
     <textarea name="body" placeholder="Say something..." ref="body" /> 
     <input type="submit" value="Send" className="button" /> 
     </form> 
    ); 
    } 
}); 

Problem: Wenn ich machen Formularkomponente innerhalb Komponente modale Formular aus und geben Sie etwas in Formulareingabe dann Ich sehe in der Konsole Ausnahme Uncaught object. Dies ist ein Stapel:

Uncaught object 
    invariant 
    ReactMount.findComponentRoot 
    ReactMount.findReactNodeByID 
    getNode 
    ... 

Wenn ich gerade Form Komponente direkt in der Komponente Eltern machen dann alles funktioniert. Könnte jemand bitte helfen?

+0

ich das gleiche Problem mit bin - meine Vermutung ist, dass die Stiftung modals das DOM manipulieren und Reagieren Sie nicht in der Lage den Überblick behalten. – dbau

+1

@dbau, Sie haben Recht. – Voldy

+1

Ich machte einen Plunk, um den Fehler zu präsentieren - http://plnkr.co/edit/Z6y5dI?p=preview. Ich habe auch an einigen Stellen gefragt: https://github.com/facebook/react/issues/1703 und https://groups.google.com/forum/#!topic/reactjs/qaG_qRMo29o – dbau

Antwort

12

Kurz gesagt, Sie tun das falsch und das ist nicht ein Bug in reagieren.

Wenn Sie irgendeine Art von Plugin verwenden, das die Dom-Knoten der reaktiven Komponente modifiziert, dann wird es die Dinge auf die eine oder andere Weise brechen.

Was Sie stattdessen tun sollten, ist die Verwendung selbst reagieren, und ergänzende CSS, um die Komponente in der Art und Weise, wie Sie für Ihre modalen Dialog möchten.

Ich würde vorschlagen, eine Komponente erstellen, die statics Komponente Eigenschaft verwendet reagieren, um ein paar Funktionen definieren renderComponent Umwickeln Ihnen einen schönen sauberen Funktionsaufruf zu geben, um zu zeigen, oder einen Dialog reagieren zu verbergen. Hier ist ein reduziertes Beispiel für etwas, das ich in der Vergangenheit benutzt habe. NB: Es verwendet jQuery, aber Sie könnten das jQ durch Standard-js-API-Aufrufe zu Dingen wie elementById und etc ersetzen, wenn Sie nicht möchten, dass der jQuery-Code.

window.MyDialog = React.createClass({ 
    propTypes: { 
     title:  React.PropTypes.string.isRequired, 
     content: React.PropTypes.string.isRequired 
    }, 
    statics: { 

     // open a dialog with props object as props 
     open: function(props) { 
      var $anchor = $('#dialog-anchor'); 
      if (!$anchor.length) { 
       $anchor = $('<div></div>') 
        .prop('id', 'dialog-anchor'); 
        .appendTo('body'); 
      } 
      return React.renderComponent(
       MyDialog(props), 
       $anchor.get(0) 
      ); 
     }, 

     // close a dialog 
     close: function() { 
      React.unmountComponentAtNode($('#dialog-anchor').get(0)); 
     } 
    }, 

    // when dialog opens, add a keyup event handler to body 
    componentDidMount: function() { 
     $('body').on('keyup.myDialog', this.globalKeyupHandler); 
    }, 

    // when dialog closes, clean up the bound keyup event handler on body 
    componentWillUnmount: function() { 
     $('body').off('keyup.myDialog'); 
    }, 

    // handles keyup events on body 
    globalKeyupHandler: function(e) { 
     if (e.keyCode == 27) { // ESC key 

      // close the dialog 
      this.statics.close(); 
     } 
    }, 

    // Extremely basic dialog dom layout - use your own 
    render: function() { 
     <div className="dialog"> 
      <div className="title-bar"> 
       <div className="title">{this.props.title}</div> 
        <a href="#" className="close" onClick={this.closeHandler}> 
       </div> 
      </div> 
      <div className="content"> 
       {this.props.content} 
      </div> 
     </div> 
    } 
}); 

Sie öffnen dann einen Dialog, durch den Aufruf:

MyDialog.open({title: 'Dialog Title', content: 'My dialog content'});

und schließen Sie es mit

MyDialog.close()

Der Dialog legt immer auf einen neuen DOM-Knoten direkt unter dem Körper mit ID 'Dialog-Anker'. Wenn Sie einen Dialog öffnen, wenn einer bereits geöffnet ist, wird das Dom auf der Basis neuer Requisiten einfach aktualisiert (oder nicht, wenn sie identisch sind).

Natürlich ist es nicht besonders nützlich, den Inhalt des Dialogs als Props-Argument zu übergeben. Ich verlängere normalerweise unten entweder parse Ablenkung -> html für den Inhalt oder bekomme etwas html über eine Ajax Anfrage innerhalb der Komponente, wenn ich stattdessen eine URL als eine Stütze zur Verfügung stelle.

Ich weiß, dass der obige Code nicht genau das ist, was Sie gesucht haben, aber ich glaube nicht, dass es einen guten Weg gibt, ein dom-modifizierendes Plugin mit reactive zu arbeiten. Sie können niemals davon ausgehen, dass die dom-Repräsentation der reaktiven Komponente statisch ist und daher nicht von einem 3rd-Party-Plugin manipuliert werden kann. Ich denke ernsthaft, wenn Sie auf diese Weise reagieren möchten, sollten Sie neu bewerten, warum Sie das Framework verwenden.

Das gesagt, ich denke, dass der Code oben ein guter Ausgangspunkt für einen Dialog ist, in dem alle Manipulation innerhalb der Komponente stattfindet, die überhaupt reaktionsfähig ist!

NB: Code wurde sehr schnell aus dem Speicher geschrieben und nicht tatsächlich in seiner aktuellen Form getestet, also tut mir leid, wenn es kleinere Syntaxfehler oder etwas gibt.

+7

Obwohl ich verstehe, dass das, was Sie sagen, richtig ist, beantwortet es nicht wirklich die Frage. Der Zweck von Foundation ist, dass Sie nicht Ihre eigenen Komponenten für so etwas wie Standard-Platten rollen müssen. Es wäre interessant zu sehen, ob es einen Weg gibt, wie das funktioniert, auch wenn es nicht "der richtige Weg" ist. Nur meine zwei Cent. – pech0rin

5

Hier ist, wie zu tun, was Mike tat, aber mit einem zf modal offenbart:

var Dialog = React.createClass({ 
    statics: { 
    open: function(){ 
     this.$dialog = $('#my-dialog'); 

     if (!this.$dialog.length) { 
     this.$dialog = $('<div id="my-dialog" class="reveal-modal" data-reveal role="dialog"></div>') 
      .appendTo('body'); 
     } 

     this.$dialog.foundation('reveal', 'open'); 

     return React.render(
     <Dialog close={this.close.bind(this)}/>, 
     this.$dialog[0] 
    ); 
    }, 
    close: function(){ 
     if(!this.$dialog || !this.$dialog.length) { 
     return; 
     } 

     React.unmountComponentAtNode(this.$dialog[0]); 
     this.$dialog.foundation('reveal', 'close'); 
    }, 
    }, 
    render : function() { 
    return (
     <div> 
     <h1>This gets rendered into the modal</h1> 
     <a href="#" className="button" onClick={this.props.close}>Close</a> 
     </div> 
    ); 
    } 
});