共计 2922 个字符,预计需要花费 8 分钟才能阅读完成。
一、高阶组件是什么?
高阶组件(HOC)是一个接管组件作为参数并返回新组件的函数。将多个组件的雷同逻辑代码,形象到 HOC 中,让组件更有结构化,更易于复用。HOC 不毁坏传入组件的个性,只通过组合造成新组件。HOC 是纯函数,没有副作用。
二、高阶组件实例
承受了组件 WrappedComponent,减少了订阅和数据刷新的操作。
// 此函数接管一个组件... | |
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) | |
}; | |
} | |
componentDidMount() { | |
// ... 负责订阅相干的操作... | |
DataSource.addChangeListener(this.handleChange); | |
} | |
componentWillUnmount() {DataSource.removeChangeListener(this.handleChange); | |
} | |
handleChange() { | |
this.setState({data: selectData(DataSource, this.props) | |
}); | |
} | |
render() { | |
// ... 并应用新数据渲染被包装的组件! | |
// 请留神,咱们可能还会传递其余属性 | |
return <WrappedComponent data={this.state.data} {...this.props} />; | |
} | |
}; | |
} |
想要减少订阅和数据刷新性能的组件,都能够应用 withSubscription,调用如下:
const CommentListWithSubscription = withSubscription( | |
CommentList, | |
(DataSource) => DataSource.getComments()); | |
const BlogPostWithSubscription = withSubscription( | |
BlogPost, | |
(DataSource, props) => DataSource.getBlogPost(props.id) | |
); |
三、只组合,不毁坏原组件
1、谬误:曾经毁坏
function logProps(InputComponent) {InputComponent.prototype.componentDidUpdate = function (prevProps) {console.log('Current props:', this.props); | |
console.log('Previous props:', prevProps); | |
}; | |
// 返回原始的 input 组件,暗示它曾经被批改。return InputComponent; | |
} | |
// 每次调用 logProps 时,加强组件都会有 log 输入。const EnhancedComponent = logProps(InputComponent); |
2、正确:组合组件
function logProps(WrappedComponent) { | |
return class extends React.Component {componentDidUpdate(prevProps) {console.log('Current props:', this.props); | |
console.log('Previous props:', prevProps); | |
} | |
render() { | |
// 将 input 组件包装在容器中,而不对其进行批改。Good! | |
return <WrappedComponent {...this.props} />; | |
} | |
} | |
} |
四、类似接口
HOC 返回的组件与原组件应放弃相似的接口。
render() {const { extraProp, ...passThroughProps} = this.props; | |
const injectedProp = someStateOrInstanceMethod; | |
return ( | |
<WrappedComponent | |
injectedProp={injectedProp} | |
{...passThroughProps} | |
/> | |
); | |
} |
五、HOC 不便调试
用 HOC 包裹组件,加上 HOC 和组件的名字,调试时输入,不便精确定位 bug 地位。
function withSubscription(WrappedComponent) {class WithSubscription extends React.Component {/* ... */} | |
WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`; | |
return WithSubscription; | |
} | |
function getDisplayName(WrappedComponent) {return WrappedComponent.displayName || WrappedComponent.name || 'Component';} |
六、render() 中禁止应用 HOC
在 render 办法中应用 HOC,每一次 HOC 都会产生一个新组件,使得原来组件被卸载,再从新加载新组件,这不仅仅是性能问题 – 从新挂载组件会导致该组件及其所有子组件的状态失落。
render() { | |
// 每次调用 render 函数都会创立一个新的 EnhancedComponent | |
// EnhancedComponent1 !== EnhancedComponent2 | |
const EnhancedComponent = enhance(MyComponent); | |
// 这将导致子树每次渲染都会进行卸载,和从新挂载的操作!return <EnhancedComponent />; | |
} |
七、静态方法与 HOC
用 HOC 包裹原组件,造成新组件,将不能拜访原始组件的静态方法。
// 定义动态函数 | |
WrappedComponent.staticMethod = function() {/*...*/} | |
// 当初应用 HOC | |
const EnhancedComponent = enhance(WrappedComponent); | |
// 加强组件没有 staticMethod | |
typeof EnhancedComponent.staticMethod === 'undefined' // true |
能够通过上面这个计划解决:
// 应用这种形式代替... | |
MyComponent.someFunction = someFunction; | |
export default MyComponent; | |
// ... 独自导出该办法... | |
export {someFunction}; | |
// ... 并在要应用的组件中,import 它们 | |
import MyComponent, {someFunction} from './MyComponent.js'; |
八、参考链接:
- React 的高阶组件怎么用?
正文完