react-flux 应用程序的可重用性/可扩展性问题

Posted

技术标签:

【中文标题】react-flux 应用程序的可重用性/可扩展性问题【英文标题】:Reusability/Scalability issues with react-flux app 【发布时间】:2015-07-09 10:58:38 【问题描述】:

问题:

有什么方法可以拥有标准的通量工作流程 - 在组件内部使用 ActionsStores 并且仍然能够将该组件用于多种不同的目的,或者如果没有,有没有办法在通量反应应用程序中拥有复杂的嵌套结构,而无需通过巨大的回调管道传播每个更改?


示例(如果问题不够清楚):

假设我有几个超级简单的自定义组件,例如 ToggleButtonSliderDatePicker 等等。它们需要可重用,因此我不能在其中使用任何操作,而是定义了回调函数。例如,DatePicker 上的 onChange 会像这样触发:

this.props.onChange(data);

我有一个自定义组件,我们称它为 InfoBox,其中包含上面描述的几个简单组件。这个组件像这样监听它的每个子组件的变化:

<DatePicker ref='startDate' onChange=this.startDate_changeHandler />

InfoBox 用于不同的目的,所以我猜它也不能绑定到特定的商店。

我还有一个自定义的Grid 组件,它可以呈现InfoBox 的许多实例。这个网格用于在不同的页面上显示不同的数据,每个页面可以有多个网格 - 所以我认为我不能将它与 Actions 和 Stores 绑定。

现在这一切都变得疯狂了,请耐心等待 - 我有几页 - 客户产品文章等.. 他们每个人都至少有一个 Grid 并且每个网格都有一些过滤器(如 search)。

页面肯定可以使用动作和存储,但页面之间有很大的相似之处,我不想复制那么多代码(不仅是方法,还有标记)。

您可能会看到它的结构相当复杂,在我看来,为嵌套组件中的每个更改实现回调方法的管道是不正确的,例如DataPicker &gt; InfoBox &gt; Grid &gt; Page &gt; Something else

【问题讨论】:

【参考方案1】:

您完全正确,更改 DatePicker 组件中的日期不应触发 Flux 操作。 Flux 动作用于更改应用程序状态,并且几乎从不查看状态,其中视图状态表示“输入框 X 包含值 Z”或“列表 Y 已折叠”。

很高兴您正在创建像Grid 等可重用组件,它将帮助您使应用程序更易于维护。

处理您的问题的方法是将组件从顶层传递到底层。这可以通过子组件或简单的道具来完成。

假设您有一个页面,其中显示了两个网格,一个网格 - 比方说 - 会议约会和一个包含待办事项的网格。现在页面本身在层次结构中太高了,不知道何时触发动作,而您的GridInfoBox 太笼统,不知道要触发哪些动作。你可以像你说的那样使用回调,但这可能有点太有限了。

所以你有一个页面,你有一个约会数组和一个待办事项数组。要渲染它并将其连接起来,你可能会有这样的事情:

var TodoActions = 
  markAsComplete: function (todo) 
    alert('Completed: ' + todo.text);
  
;

var InfoBox = React.createClass(
  render: function() 
    return (
      <div className="infobox">
        React.createElement(this.props.component, this.props)
      </div>
    );
  
);

var Grid = React.createClass(
  render: function() 
    var that = this;
    return (
      <div className="grid">
        this.props.items.map(function (item) 
          return <InfoBox component=that.props.component item=item />;
        )
      </div>
    );
  
);

var Todo = React.createClass(
  render: function() 
    var that = this;
    return (
      <div>
        Todo: this.props.item.text
        <button onClick=function ()  TodoActions.markAsComplete(that.props.item); >Mark as complete</button>
      </div>
    );
  
);

var MyPage = React.createClass(
  getInitialState: function () 
    return 
      todos: [text: 'A todo']
    ;
  ,
  render: function() 
    return (
      <Grid items=this.state.todos component=Todo />
    );
  
);

React.render(<MyPage />, document.getElementById('app'));

如您所见,GridInfoBox 都知道的很少,除了一些数据传递给它们,并且它们应该在底部渲染一个知道如何触发动作的组件。 InfoBox 也将它的所有 props 传递给 Todo,这将给 Todo 传递给 InfoBox 的 todo 对象。

所以这是处理这些事情的一种方法,但这仍然意味着您正在从一个组件向下传播道具。在某些情况下,您有深度嵌套,传播变得乏味,并且很容易忘记添加它,这会进一步分解组件。对于这些情况,我建议您查看 React 中的上下文,这非常棒。这是对上下文的一个很好的介绍:https://www.tildedave.com/2014/11/15/introduction-to-contexts-in-react-js.html

编辑

更新您的评论的答案。为了概括示例中的Todo,使其不知道要显式调用哪个操作,您可以将其包装在一个知道的新组件中。

类似这样的:

var Todo = React.createClass(
  render: function() 
    var that = this;
    return (
      <div>
        Todo: this.props.item.text
        <button onClick=function ()  this.props.onCompleted(that.props.item); >Mark as complete</button>
      </div>
    );
  
);

var AppointmentTodo = React.createClass(
  render: function() 
    return <Todo ...this.props onCompleted=function (todo)  TodoActions.markAsComplete(todo);  />;
  
);

var MyPage = React.createClass(
  getInitialState: function () 
    return 
      todos: [text: 'A todo']
    ;
  ,
  render: function() 
    return (
      <Grid items=this.state.todos component=AppointmentTodo />
    );
  
);

因此,现在不是让MyPageTodo 传递给Grid,而是将AppointmentTodo 传递给仅作为知道特定操作的包装组件,从而释放Todo 以只关心渲染它。这是 React 中非常常见的模式,其中您的组件只是将渲染委托给另一个组件,并将 props 传递给它。

【讨论】:

感谢您的回答,但在接受之前我有一个小要求 - 请在您的示例中包括如何使用 Todo 组件来处理检查约会 i> 以及 Todos,我不确定您是否需要将操作作为属性传递,或者有没有更好的方法? 我不确定我是否理解。在我的示例中,待办事项和约会是两个独立的事物,彼此没有任何关系。这也是我在示例中省略约会的原因,因为您只需复制我在 todos 中给出的方法。你能详细说明你想让我展示什么吗?在待办事项的上下文中,“检查约会”是什么意思? 可以说appointments 也是与todo 列表完全相同的清单,它们只是使用来自不同商店的数据。在这种情况下,我需要能够重用 Todo 类。 我已经更新了我的答案。希望它能回答你的问题。 我希望有更灵活的解决方案,但我意识到可能没有,谢谢您的时间。

以上是关于react-flux 应用程序的可重用性/可扩展性问题的主要内容,如果未能解决你的问题,请参考以下文章

不同应用状态结构级别的reducer的可重用性

iOS 中 AudioUnit Graph 的可重用性

Qt C++ 项目中 Xamarin 项目中代码的可重用性

List 中的可重用性支持 - SwiftUI

Android活动可重用性

我们能否增加这种面向密钥的访问保护模式的可重用性?