20

我正在尝试将 zurb 显示与表单集成到反应组件中。到目前为止,下一个代码正确显示了模态形式:

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

Form组件非常标准:

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

问题:当我在模态表单组件中呈现表单组件并在表单输入中输入内容时,我在控制台异常中看到Uncaught object。这是一个堆栈:

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

如果我只是直接在父组件中渲染表单组件,那么一切正常。有人可以帮忙吗?

4

2 回答 2

12

简而言之,您做错了,这不是反应中的错误。

如果您使用任何类型的插件来修改 react 组件的 dom 节点,那么它将以一种或另一种方式破坏事物。

相反,您应该做的是使用 react 本身和互补的 css,以您希望模态对话框的方式定位组件。

我建议创建一个组件,使用 react 的statics组件属性来定义几个函数包装renderComponent,以便为您提供一个很好的干净函数调用来显示或隐藏反应对话框。这是我过去使用过的一个简化示例。elementById注意:它确实使用了 jQuery,但是如果你不想要 jQuery 代码,你可以用标准的 js api 调用来替换 jQ 。

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

然后通过调用打开一个对话框:

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

并关闭它

MyDialog.close()

对话框始终附加到 ID 为“dialog-anchor”的 body 正下方的新 dom 节点。如果您在一个对话框已经打开时打开一个对话框,它只会根据新的道具更新 dom(如果它们相同,则不会更新)。

当然,将对话框的内容作为 props 参数传递并不是特别有用。我通常在下面扩展以解析 markdown -> html 的内容,或者在提供 url 作为 prop 时通过组件内的 ajax 请求获取一些 html。

我知道上面的代码并不是你想要的,但我不认为有一个好方法可以让一个 dom 修改插件与 react 一起工作。你永远不能假设 react 组件的 dom 表示是静态的,因此它不能被 3rd 方插件成功操作。老实说,我认为如果你想以这种方式使用 react,你应该重新评估你为什么使用这个框架。

也就是说,我认为上面的代码是一个很好的起点,其中所有操作都发生在组件内部,这毕竟是 reactjs 的全部内容!

注意:代码是从内存中快速编写的,并没有以当前的形式实际测试过,如果有一些小的语法错误或其他东西,很抱歉。

于 2014-06-24T21:23:12.190 回答
5

以下是迈克所做的事情,但使用了 zf 显示模式:

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>
    );
  }
});
于 2015-05-31T06:03:25.773 回答