return ;
}
}
有没有发现,CommentList和BlogPost不同 - 它们在数据源DataSource上调用不同的方法,且渲染不同的结果。但它们的大部分实现都是一样的:
-
在挂载时,向
DataSource
添加一个更改侦听器。 -
在侦听器内部,当数据源发生变化时,调用
setState
。 -
在卸载时,删除侦听器。
你可以想象,在一个大型应用程序中,这种订阅DataSource和调用setState的模式将一次又一次地发生。我们需要一个抽象,允许我们在一个地方定义这个逻辑,并在许多组件之间共享它。这正是高阶组件擅长的地方。
对于订阅了DataSource的组件,比如CommentList和BlogPost,我们可以编写一个创建组件函数。该函数将接受一个子组件作为它的其中一个参数(可以是多个参数),该子组件将订阅数据作为 prop。
//withSubscription为高阶组件,复用逻辑提取到里面
const CommentListWrapper = withSubscription(
CommentList,
(DataSource) => DataSource.getComments()
);
const BlogPostWrapper = withSubscription(
BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id)
);
//CommentListWrapper、BlogPostWrapper分别为扩展(共享逻辑)之后的新组件
第一个参数是被包装组件。第二个参数通过DataSource和当前的 props 返回我们需要的数据。当渲染这两个组件时,CommentList和BlogPost将传递一个data prop,其中包含从DataSource检索到的最新数据:
// 此函数接收一个组件
function withSubscription(WrappedComponent, selectData) {
// 并返回另一个组件
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props) //DataSource全局数据源
};
}
componentDidMount() {
// 负责订阅相关的操作
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// 清除订阅
Da