我正在开发一个React应用程序,我的第一个,我正在努力实现如何实现用户交互式弹出窗口。我有一个业务要求,有一个带有yes / no按钮的popover。此弹出窗口由一个按钮(“pobtn”)触发,该按钮位于视图中表格的一行中:
+- View ---------------------+ +- View ---------------------+
| +- Table ----------------+ | click | +- Table ----------------+ |
| | +- Row --------------+ | | --> | | +- Row --------------+ | |
| | | ... | | | pobtn | | | ... | | |
| | +--------------------+ | | | | +--------------------+ | |
| | +- Row --------------+ | | ,--------. +- Row --------------+ | |
| | | ... [pobtn] | | | | Yes/No |>| ... [pobtn] | | |
| | +--------------------+ | | `--------' +--------------------+ | |
| | +- Row --------------+ | | | | +- Row --------------+ | |
| | | ... | | | | | | ... | | |
| | +--------------------+ | | | | +--------------------+ | |
| | ... | | | | ... | |
| +------------------------+ | | +------------------------+ |
+----------------------------+ +----------------------------+
视图,表格和行都是组件。表格数据是在View中获取的,并通过道具推送到Table,然后逐渐进入Row,我理解这是“正确的方法”,并且有意义。当地没有太多的地方。
麻烦来自popover。这样做的“正确方法”似乎是在每个按钮旁边都包含一个Popover组件,并且推动道具向下隐藏/可见,我想。这看起来并不是很棒,但在我的脑海里更接近正确的方式。
然而,react-bootstrap popover(因为时间而使用)似乎没有这样工作:
var content = <MyRowPopoverContent/>;
<OverlayTrigger trigger='click' placement='left' overlay={<Popover>{content}</Popover>
<button className="btn btn-primary small"><i className="fa fa-trash-o"></i> Delete</button>
</OverlayTrigger>
单击触发按钮时,它会创建一个附加到主体的DIV,并将其自身定位在触发元素旁边,类似于它的正常工作方式(无反应)。看起来我可以将DIV附加到另一个容器,但是没有记录得很好。无论如何,叠加内容(即MyRowPopoverContent)类似于:
this.handleNoClick: function(){
// Re-click the button to close; gross.
$('[data-row-id="'+this.props.row.key+'"]').find('.fa-trash-o').parents('button').first().click();
},
this.handleYesClick: function(){
// Do stuff...update store which would re-render the view.
// Re-click the button to close; gross.
$('[data-row-id="'+this.props.row.key+'"]').find('.fa-trash-o').parents('button').first().click();
},
this.render: function(){
<div>
<div>Are you sure?</div>
<input placeholder="Reason"/>
<button onClick={this.handleYesClick}>Yes</button> <button onClick={this.handleNoClick}>No</button>
</div>
}
我开始实现handleYesClick
函数,尝试进行错误处理,异步事件等等,这一切看起来都很粗略,或者至少是脆弱的。我想问题是:我需要一个交互式弹出框,我该怎么做?看起来弹出窗口会成为按钮或行的本地状态的一部分,或者这可能会像大多数事情一样爬到顶端。
由于react-bootstrap已经提供了一个,所以使用它会很好,但我不确定如何将其与其他所有东西“挂钩”。
更新:如果它是一个简单的静态弹出窗口,那将是蛋糕;通过道具显示/隐藏它并点击pobtn
非常简单。我努力的部分是popover中的交互式内容 - 让做某事(比如更新商店的事件),显示微调器,确定是否有效,显示错误消息或消失。即使单击“否”按钮并使弹出窗口消失也不清楚(我目前使用jQuery和.click()
按钮再次找到它。)通过来自父级的道具来执行 全部吓人...
答案 0 :(得分:1)
假设您将popover封装到PopoverMenu
组件中。这是一个反应友好的模式,父母处理其孩子的事件:
var Table = React.createClass({
handlePopoverClick(selection, meta) {
// selection - the selection ('Yes' or 'No' in your case)
// meta - anything you want to know about the caller
},
render: function() {
var open = /* boolean logic to determine if popover is open or closed* /;
// key idea is to pass the child a handler from the parent
<PopoverMenu handler={this.handlePopoverClick} open={open} ... />
...
}
});
var PopoverMenu = React.createClass({
handleClick: function(selection, meta) {
this.props.handler(selection, meta);
},
render: function() {
...
//somewhere you render the 'Yes' Button of this popover
<Button onClick={this.handleClick.bind(this, 'Yes', {row: 2})} />
}
});
PopoverMenu
组件是无状态的;它知道足以渲染。它的处理程序接收click事件,然后根据需要调整PopoverMenu
的道具。神奇的是.bind
,它允许您为处理程序注入特定于调用者的信息以作出反应。 (您可以想象.bind
调用发生在map
调用中Yes
和{row :2}
是动态变量。)请注意,您可以使用单个处理程序处理所有弹出窗口选项父母,并且您可以轻松地跟踪,作为父母的状态(例如,行)的一部分,任何呼叫的等待/成功/失败状态。这可能看起来很吓人,但说逻辑需要住在某处:)如果某个地方不是孩子,那就更好了,因为React方式是无国籍的孩子。当信息从父母传给孩子时,州自然成为道具。
那就是说,如果你的父母做了太多的簿记,你不能从儿童组件中获得干净,自足的行为,你可以将逻辑推入孩子,通常是以儿童为代价可重用性。孩子处理自己的打开/关闭状态和等待/错误/成功状态是合理的,也是可能的。如果你走这条路线,你可以使用的一种模式是让孩子处于等待状态,除非你通过道具从父母那里得到一个匹配的值。例如,如果用户进行菜单选择&#39; X&#39;这需要一个回调,孩子做setState{ selection: 'X'}
并等待父母通过道具证实(反映商店的状态):
if (this.state.selection !== this.props.selection) {
//render component as waiting
} else {
//render as normal
}
关于弹出窗口的打开/关闭状态,如果您使用像ButtonDropdown
这样的组件来管理自己的打开/关闭状态会更容易。 (您可能必须在下拉列表中设置一个空的onSelect
处理程序,以便在选择时自动关闭。)