分享

javascript – react-flux应用程序的可重用性/可伸缩性问题

 印度阿三17 2019-06-28

问题:

有没有办法有一个标准的助焊剂工作流程 – 在组件内部使用动作和商店,仍然能够将这个组件用于多种不同的目的,或者如果没有,有没有办法在助焊剂反应应用程序中使用复杂的嵌套结构通过巨大的回调管道传播每一个变化?

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

假设我有一些超级简单的自定义组件,如ToggleButton,Slider,DatePicker等等.它们需要可重用,所以我不能在它们内部使用任何动作,而是我定义了回调函数.例如,DatePicker上的onChange会像这样触发:

this.props.onChange(data);

我有一个自定义组件让我们称之为InfoBox,其中包含上面描述的几个简单组件.该组件侦听每个子节点的更改,如下所示:

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

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

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

现在这里一切都变得疯狂,忍受我 – 我有几页 – 客户,产品,文章等.每个人都有至少一个网格,每个网格都有一些过滤器(如搜索).

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

正如你可能看到它的结构非常复杂,在我看来,对于像DataPicker>这样的嵌套组件中的每个变化都实现回调方法的管道线是不对的.资讯盒&GT网格和GT;页面&GT还有别的.

解决方法:

你完全正确的做法是更改DatePicker组件中的日期不应该触发Flux操作. Flux动作用于改变应用程序状态,并且几乎从不查看视图状态意味着“输入框X包含值Z”或“列表Y被折叠”的状态.

您正在创建可重用的组件(如Grid等)非常棒,它可以帮助您使应用程序更易于维护.

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

假设你有一个页面,它显示了两个网格,一个网格 – 比方说 – 会议约会和一个带有待办事项的网格.现在,页面本身在层次结构中太高,无法知道何时触发操作,并且Grid和InfoBox过于笼统,无法知道要触发的操作.你可以像你说的那样使用回调,但这可能有点过于局限.

所以你有一个页面,你有一系列约会和一系列待办事项.要渲染并连接它,你可能会有这样的事情:

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'));

如您所见,Grid和InfoBox都知道的很少,除了一些数据传递给它们,并且它们应该在底部呈现一个知道如何触发动作的组件. InfoBox还将其所有道具传递给Todo,这为Todo提供了传递给InfoBox的待办事项对象.

所以这是处理这些事情的一种方法,但它仍然意味着你在组件之间传播道具.在某些情况下,如果您有深度嵌套,那么传播会变得乏味,并且很容易忘记添加它会使组件进一步向下破坏.对于这些情况,我建议您查看React中的上下文,这非常棒.以下是对上下文的一个很好的介绍:https://www./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} />
    );
  }
});

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

来源:https://www./content-1-277251.html

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多