这是一个更多的风格/理论问题,因为我认为这两种方法都有效。这是场景:
我有一个InfiniteList组件,我想保持通用。它从父级获取所有项目ID的当前列表,然后确定它实际呈现的内容。为此,我基本上从列表中提取适当的ID,然后从商店中通过ID获取完整数据。
我的问题是:为了保持通用性,显然无限列表组件无法真正硬编码它应该从哪个商店获取完整的商品数据(比方说我有10种不同类型的商品都有自己的商品商店)。但是,对我来说更有意义的是,滚动并更改正在显示的项目集是状态。所以,你认为它是否有意义:
A)将IDS列表作为道具传递,以及从父组件中添加/删除侦听器,以便列表组件知道要收听谁?
B)或者只是传递列表和作为道具可用的全部项目数据并让父组件听取相应的商店更有意义吗?
背后的一部分动机"倾听"如果商店没有商品,它必须提取它们,所以我需要在itemStore更新后重新呈现列表。
答案 0 :(得分:2)
我会选择 B ,原因如下:
1)我认为这会产生最通用的组件,因为它不需要知道数据来自何处或如何更新。
2)组件没有状态。
3)监听商店活动和更新组件状态的代码可能很短,你不会因为将其移入组件而获得很大的好处。我看到的唯一优势是将存储事件处理移动到组件中,因此您不必重写它。但通过这样做,您可以强制您的组件拥有状态。也许在这种情况下,它是直截了当的无所谓。这实际上取决于应用程序。如果层次结构中较高的组件(InfiniteList的父级)也将重新渲染来自同一商店的事件,那么我将避免让InfiniteList在同一事件上重新呈现自身。如果你的InfiniteList 是唯一需要在该事件上更新的组件,那么将状态置于InfiniteList中是有意义的,但这似乎不太可能适用于所有情况。所以,我再次倾向于B更为通用。
话虽如此, if 你真的想保存重写事件处理逻辑,如果你从React教程中使用相同的方法,我会利用这个事实并且只是通过将商店本身作为道具。在示例中,存储是通过继承自EventEmitter.prototype
创建的。如果您以这种方式创建每个商店,则表示它将具有addListener()
和removeListener()
方法。此外,您可以要求每个商店都有方法getItemIds()
和`getItem(id)'。如果您想明确强制传递到React组件的对象具有所有这些方法,则可以使用propTypes with isRequired。例如:
//YourComponent.js
var YourComponent = React.createClass({
propTypes:{
// assuming ListModel has been defined with the methods you need
listModel: React.PropTypes.instanceOf( ListModel ).isRequired,
// assuming you're using the EventEmitter, like in React example code
modelEvent: React.PropTypes.string.isRequired
},
getInitialState: function(){
// start with an empty array
return { items: [] };
},
componentDidMount: function(){
var evt_handler;
// when the model changes, get the list again
evt_handler = ( function(){
this.setState( { items: this.props.listModel.getItemIds() } );
}.bind( this ) ); // bind to maintain context
// register for events
this.props.listModel.addListener( this.props.modelEvent, evt_handler );
},
render: function(){
...do your filtering, make it pretty
}
});
这显然不如 B 的无状态方法更通用,并且实际上只是传递函数本身的风格替代方法,但不管怎样,我都使用propTypes
isRequired
用于功能。