React高阶组件:函数式与类式写法辨析及适用场景
Are Both Approaches Higher-Order Components?
First, the short answer: No, only the first one is a true HOC. Here's why:
- The first approach (
withSubscription) is a function that accepts aWrappedComponentandselectDataparameter, then returns a new enhanced component. This fits the exact HOC definition from React's official docs. - The second approach (
WithSubscription) is a regular class component that accepts acomponentprop (andselectData) to render. This is actually a variant of the Component-as-Prop pattern (a cousin of Render Props), not an HOC. HOCs are always functions, not components themselves.
Breakdown of Each Approach
1. The HOC Function (withSubscription)
This is the classic HOC implementation:
function withSubscription(WrappedComponent, selectData) { // ...and returns another component... return class extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { data: selectData(DataSource, props) }; } componentDidMount() { // ... that takes care of the subscription... DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ data: selectData(DataSource, this.props) }); } render() { // ... and renders the wrapped component with the fresh data! // Notice that we pass through any additional props return <WrappedComponent data={this.state.data} {...this.props} />; } }; }
Usage:
// Pre-create the enhanced component once const BlogPostWithSubscription = withSubscription( BlogPost, (DataSource) => DataSource.getComments() ); // Use it like any other component <BlogPostWithSubscription />
2. The Component-as-Prop Class (WithSubscription)
This is a flexible component that takes another component as a prop to render. I fixed a small bug in your original code (referencing this.props.component instead of <component /> to avoid rendering an invalid HTML tag):
class WithSubscription extends React.Component { constructor({ component, selectData, ...props }) { super(props); this.handleChange = this.handleChange.bind(this); this.state = { data: selectData(DataSource, props) }; } componentDidMount() { DataSource.addChangeListener(this.handleChange); } componentWillUnmount() { DataSource.removeChangeListener(this.handleChange); } handleChange() { this.setState({ data: selectData(DataSource, this.props) }); } render() { return <this.props.component data={this.state.data} {...this.props} />; } }
Usage:
// Dynamically pass the component and select logic each time you use it <WithSubscription component={BlogPost} selectData={(DataSource) => DataSource.getComments()} />
When to Use Each Approach
Use the HOC Function If:
- You want to pre-configure an enhanced component for repeated use. For example, if you need the subscription logic attached to
BlogPostin multiple places, creatingBlogPostWithSubscriptiononce keeps your code DRY. - You're building reusable utilities or library code. HOCs like Redux's
connector React Router'swithRouterfollow this pattern because they let users wrap their components with fixed logic. - You prefer a more "static" enhancement—once the HOC is applied, the wrapped component and logic are tied together unless you create a new enhanced component.
Use the Component-as-Prop Class If:
- You need dynamic flexibility—for example, using the same subscription logic with different components (e.g., sometimes
BlogPost, sometimesCommentList) without pre-creating multiple enhanced components. - You want to configure the logic at render time instead of upfront. This is great for one-off uses or cases where the select logic or target component might change based on props.
- You prefer a more explicit, declarative approach where the relationship between the enhancer and component is visible directly in the JSX.
内容的提问来源于stack exchange,提问作者Shawn
相关产品推荐
相关产品推荐

