我正在尝试将zurb reveal与form集成到react组件中。到目前为止,下一个代码正确显示模态形式:
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">×</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
...
如果我只是在父组件中直接呈现表单组件,那么一切都可以正常工作。有人能帮忙吗?
总之,你这样做是错误的,这是而不是 react中的错误。
如果你使用任何类型的插件来修改react组件的dom节点,那么它将会以这样或那样的方式破坏东西。
你应该做的是使用react本身和互补的css,以你想要的方式来定位组件。
我建议创建一个组件,使用react的statics
组件属性来定义两个包装renderComponent
的函数,以便为您提供一个漂亮的干净的函数调用来显示或隐藏react对话框。这是我过去用过的一个简短的例子。注:它确实使用jQuery,但如果你不想要jQuery代码,你可以用标准的js api调用elementById
等来代替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表示是静态的,因此它不能被第三方插件成功地操纵。我真诚地认为,如果你想以这种方式使用react,你应该重新评估为什么要使用这个框架。
也就是说,我认为上面的代码是一个很好的对话框的起点,在这个对话框中,所有的操作都发生在组件内部,这就是react的全部内容!
NB:代码是从内存中编写的非常快,并没有实际测试它的当前形式,所以很抱歉,如果有一些小的语法错误或其他东西。
下面是如何做到Mike所做的,但是使用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>
);
}
});