您完全正确,更改 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 也将它的所有 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} />
);
}
});
因此,现在不是让MyPage 将Todo 传递给Grid,而是将AppointmentTodo 传递给仅作为知道特定操作的包装组件,从而释放Todo 以只关心渲染它。这是 React 中非常常见的模式,其中您的组件只是将渲染委托给另一个组件,并将 props 传递给它。