[我使用] react-bootstrap的popover“反应方式”吗?

时间:2015-06-16 14:44:48

标签: reactjs react-bootstrap

我正在开发一个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()按钮再次找到它。)通过来自父级的道具来执行 全部吓人...

1 个答案:

答案 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处理程序,以便在选择时自动关闭。)