我们目前正在重构使用更高阶的组件。在大多数情况下,这使一切变得更加简单。
我们有HOC用于获取数据和收听商店。例如,我们有connectStores
,它包含要订阅的商店列表和获取数据的函数(作为额外的道具传递):
connectStores(FooComponent, [FooStore], function (props) {
return {
foo: FooStore.get(props.id),
};
});
但是,有一些地方从商店获取数据的过程取决于状态。例如,我们有一个SelectFooPopup,它向用户显示可供选择的项目列表。但是还有一个搜索框来过滤列表,所以目前组件直接监听商店,然后像这样获取数据本身:
componentDidMount() {
var self = this;
this.listenTo(FooStore, 'change', function () {
self.forceUpdate();
});
}
render() {
var items = FooStore.search(this.state.searchText);
// render...
}
(this.listenTo
是我们试图用HOC代替的mixin,所以我们可以使用ES6类)
我可以想到几个选项,但我不喜欢它们中的任何一个:
componentDidMount() {
var self = this;
this.listener = function () {
self.forceUpdate();
};
FooStore.on('change', this.listener);
}
componentWillUnmount() {
if (this.listener) {
FooStore.removeListener('change', this.listener);
}
}
render() {
var items = FooStore.search(this.state.searchText);
// render...
}
我真的很讨厌必须手动执行此操作。我们在使用listenTo mixin之前就这样做了,而且很容易出错。
当订阅必须直接从服务器获取数据而不是使用预先填充的商店时,这也无济于事。
class SelectFooPopup extends React.Component {
render() {
var items = FooStore.search(this.state.searchText);
}
}
connectStores(SelectFooPopup, [FooStore], function (props) {
// Just to forceUpdate
return {};
});
这对我来说感觉不对。当我们开始优化纯组件并且突然子组件不再重新渲染时,这就会出问题。
class SelectFooPopup extends React.Component {
render() {
var items = filterSearch(this.props.items, this.state.searchText);
}
}
connectStores(SelectFooPopup, [FooStore], function (props) {
return {
items: FooStore.getAllItems(),
};
});
但是现在我必须有一个完全独立的filterSearch函数。这不应该是商店的方法吗?
此外,它在这个例子中没有太大的区别,但我有其他组件有类似的问题 他们从服务器获取数据,而不是订阅预先填充的商店。在这些情况下 数据集太大而无法全部发送并在以后过滤,因此在获取数据时,searchText必须可用。
有时这是正确的解决方案。但它感觉不对劲。 searchText是 this 组件状态的一部分。它属于呈现搜索框的相同位置。
将它移到一个单独的组件是令人困惑和人为的。
function parentState(Component, getInitialState) {
class ParentStateContainer extends React.Component {
constructor(props) {
super();
this.setParentState = this.setParentState.bind(this);
if (getInitialState) {
this.state = getInitialState(props);
} else {
this.state = {};
}
}
setParentState(newState) {
this.setState(newState);
}
render() {
return <Component {...this.props} {...this.state} setParentState={ this.setParentState } />;
}
}
return ParentStateContainer;
}
// Usage:
parentState(SelectFooPopup, function (props) {
return {
searchText: '',
};
});
// In handleSearchText:
this.props.setParentState({ searchText: newValue });
这也感觉非常错误,我应该把它扔掉。
在React中,我们有两个级别:props
和state
。
在我看来,实际上有4个级别要考虑:
我们可以使用HOC实现第2层。但是我们如何实现第4层?