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

Javascript react-flux应用程序的可重用性/可伸缩性问题,javascript,reactjs,reactjs-flux,flux,Javascript,Reactjs,Reactjs Flux,Flux,问题: 有没有办法拥有一个标准的flux工作流-在组件内部使用操作和存储,并且仍然能够将该组件用于多种不同的目的,或者如果没有,有没有办法在flux react应用程序中拥有复杂的嵌套结构,而不必通过一个巨大的回调管线传播每个更改 示例(如果问题不够清楚): 假设我有两个超级简单的自定义组件,比如ToggleButton、Slider、DatePicker等等。它们需要可重用,因此我不能在它们内部使用任何操作,而是定义了回调函数。例如,日期选择器上的onChange如下所示: this.pro

问题:

有没有办法拥有一个标准的flux工作流-在组件内部使用操作和存储,并且仍然能够将该组件用于多种不同的目的,或者如果没有,有没有办法在flux react应用程序中拥有复杂的嵌套结构,而不必通过一个巨大的回调管线传播每个更改


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

假设我有两个超级简单的自定义组件,比如ToggleButton、Slider、DatePicker等等。它们需要可重用,因此我不能在它们内部使用任何操作,而是定义了回调函数。例如,日期选择器上的
onChange
如下所示:

this.props.onChange(data);
<DatePicker ref='startDate' onChange={this.startDate_changeHandler} />
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'));
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} />
    );
  }
});
我有一个自定义组件,我们称之为InfoBox,它包含上面描述的几个简单组件。此组件侦听其每个子组件的更改,如下所示:

this.props.onChange(data);
<DatePicker ref='startDate' onChange={this.startDate_changeHandler} />
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'));
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} />
    );
  }
});

InfoBox用于不同的目的,因此我猜它也不能绑定到特定的存储

我还有一个定制的网格组件,可以呈现InfoBox的许多实例。这个网格用于在不同的页面上显示不同的数据,每个页面可以有多个网格,所以我认为我不能用操作和存储绑定它

现在一切都变得疯狂了,请耐心听我说——我有几页——客户、产品、文章等等。。每个网格至少有一个网格,每个网格都有一些过滤器(如搜索)

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


正如您可能看到的,它的结构非常复杂,在我看来,为嵌套组件中的每个更改(如
DataPicker>InfoBox>Grid>Page>Something
)实现回调方法的管道是不正确的

更改
日期选择器
组件中的日期不应触发流量操作,这一点绝对正确。Flux操作用于更改应用程序状态,并且几乎从不使用视图状态,其中视图状态表示“输入框X包含值Z”或“列表Y已折叠”

创建可重用组件(如
Grid
等)非常好,它将帮助您提高应用程序的可维护性

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

假设您有一个页面,其中显示两个网格,一个网格是会议约会,另一个网格是待办事项。现在,页面本身在层次结构中的位置太高,无法知道何时触发操作,而且您的
Grid
InfoBox
过于笼统,无法知道要触发哪些操作。您可以像您所说的那样使用回调,但这可能有点太有限了

因此,您有一个页面,有一个约会数组和一个待办事项数组。要渲染它并将其连接起来,您可能会遇到以下情况:

this.props.onChange(data);
<DatePicker ref='startDate' onChange={this.startDate_changeHandler} />
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'));
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
pass
Todo
传递到
Grid
,而是传递
AppointmentTodo
,它只充当知道特定操作的包装器组件,将
Todo
释放为只关心呈现它。这是React中非常常见的模式,其中您的组件只是将渲染委托给另一个组件,并向其传递道具。

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