【问题标题】:Is [my use of] react-bootstrap's popover "the react way"?[我使用] react-bootstrap 的弹出框是“反应方式”吗?
【发布时间】:2015-06-16 14:44:47
【问题描述】:

我正在开发一个 React 应用程序,这是我的第一个应用程序,我正在努力解决如何实现用户交互式弹出框。我有一个业务需求,需要有一个带有是/否按钮的弹出框。此弹出框由一个按钮(“pobtn”)触发,该按钮位于视图中表格的一行中:

+- View ---------------------+          +- View ---------------------+
| +- Table ----------------+ |   click  | +- Table ----------------+ |
| | +- Row --------------+ | |    -->   | | +- Row --------------+ | |
| | | ...                | | |   pobtn  | | | ...                | | |
| | +--------------------+ | |          | | +--------------------+ | |
| | +- Row --------------+ | |   ,--------. +- Row --------------+ | |
| | | ...        [pobtn] | | |   | Yes/No |>| ...        [pobtn] | | |
| | +--------------------+ | |   `--------' +--------------------+ | |
| | +- Row --------------+ | |          | | +- Row --------------+ | |
| | | ...                | | |          | | | ...                | | |
| | +--------------------+ | |          | | +--------------------+ | |
| | ...                    | |          | | ...                    | |
| +------------------------+ |          | +------------------------+ |
+----------------------------+          +----------------------------+

View、Table 和 Row 都是组件。表格数据在 View 中获取并通过 props 推送到 Table,然后滴入 Row,我理解这是“正确的方法”,并且是有道理的。那里没有多少地方州。

问题在于弹出框。我猜,做到这一点的“正确方法”似乎包括每个按钮旁边的 Popover 组件并将道具向下推以隐藏/可见。这似乎不是很好,但更接近我认为的正确方法。

但是,react-bootstrap 弹出窗口(我使用它是因为时间)似乎并没有以这种方式工作:

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 非常简单。我挣扎的部分是弹出框内的交互式内容——让 一些事情(比如更新商店的事件)、显示一个微调器、确定某件事是否有效、显示错误消息或消失。即使单击“否”按钮并使弹出框消失也不清楚(我目前使用 jQuery 和 .click() 再次找到它。)通过父级的道具来做 似乎很可怕。 ..

【问题讨论】:

  • 您是否可以将所有逻辑保留在弹出窗口中,而不是将逻辑保留在更高级别的组件中并传递回调,然后单击按钮将调用这些回调?
  • 重新阅读您的问题并在下面提供替代方案。 React 方式是无状态的孩子,但是,如果你觉得父母的逻辑太胖了,你可以把逻辑推到树下。这是封装和无状态之间的权衡。

标签: reactjs react-bootstrap


【解决方案1】:

假设您将弹出框封装到 PopoverMenu 组件中。这是一个对 React 友好的模式,其中父母处理其孩子的事件:

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 组件是无状态的;它只知道渲染。它的处理程序接收点击事件,然后根据需要调整PopoverMenu 的道具。神奇之处在于.bind,它允许您注入特定于调用者的信息以供处理程序作出反应。 (您可以想象.bind 出现在map 调用中,其中Yes{row :2} 是动态变量。)请注意,您可以使用父级中的单个处理程序处理所有弹出框选择,并且您可以轻松地作为父状态(例如行)的一部分,跟踪任何调用的等待/成功/失败状态。这可能看起来很可怕,但是说逻辑需要存在于某个地方:) 如果那个地方不是孩子,那就更好了,因为 React 方式是无状态的孩子。当信息从父级流向子级时,状态自然会成为道具。

也就是说,如果您的父级记账太多,而您没有从子级组件中获得干净、独立的行为,您可以将逻辑下推到子级,通常以子级可重用性为代价。孩子处理自己的打开/关闭状态和等待/错误/成功状态是合理和可能的。如果你走这条路,你可以使用的一种模式是让孩子处于等待状态,直到并且除非你通过道具从父母那里收到匹配的值。例如,如果用户进行了需要回调的菜单选择“X”,则子级执行setState{ selection: 'X'} 并等待父级通过道具(反映商店的状态)证实:

if (this.state.selection !== this.props.selection) {
  //render component as waiting
} else {
  //render as normal
}

关于弹出框的打开/关闭状态,如果您改为使用像ButtonDropdown 这样的组件会更容易,它管理自己的打开/关闭状态。 (您可能需要在下拉列表中设置一个空的 onSelect 处理程序,以便在选择时自动关闭。)

【讨论】:

    猜你喜欢
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 2016-06-21
    相关资源
    最近更新 更多