初识React中的High Order Component
也可以在这里看:http://leozdgao.me/chushi-hoc/ 我们都知道,如果使用ES6 Component语法写React组件的话,mixin是不支持的。而mixin作为一种抽象和共用代码的方案,许过库(比如 如果希望使用ES6 Component,有希望可以用一个像mixin一样的方案的话,可以使用 什么是High Order Component?High Order Component,下面统一简称为HOC。我理解的HOC实际上是这样一个函数: hoc :: ReactComponent -> ReactComponent 它接受一个ReactComponent,并返回一个新的ReactComponent,这一点颇有函数式编程的味道。由于是一个抽象和公用代码的方案,这个新的ReactComponent主要包含一些共用代码的逻辑或者是状态,用一个例子来解释更加直观: const connect = (mapStateFromStore) => (WrappedComponent) => { class InnerComponent extends Component { static contextTypes = { store: T.object } state = { others: {} } componentDidMount () { const { store } = this.context this.unSubscribe = store.subscribe(() => { this.setState({ others: mapStateFromStore(store.getState()) } }) } componentWillUnmount () { this.unSubscribe() } render () { const { others } = this.state const props = { ...this.props,...others } return <WrappedComponent {...props} /> } } return InnerComponent } 这个例子中定义的connect函数其实和 始终要记住的是,HOC最终返回的是一个新的ReactComponent。 要使用HOC的话可以这样: class MyContainer extends Component { ... } export connect(() => ({}))(MyContainer) 其实我们还发现HOC的函数类型和class decorator是一样的,所以可以这样: @connect(() => ({})) class MyContainer extends Component { ... } export MyContainer 但是HOC不是decorator,不能保证decorator最终一定进入ES的规范中,然而HOC始终是那个函数。 与mixin作比较既然HOC的目的和mixin类似,那么我们来比较下这两种方案的区别: 首先,mixin是react亲生的,而HOC是社区实践的产物。其实这一点无关紧要,关键是讨论方案是否给开发带来便利,而且从趋势来看,并不看好mixin。
不过我们还是先来看下mixin的使用场景:
第一个应用场景Lifecycle Hook通常是在React组件生命周期函数中做文章,最典型的就是对Store的监听和保证unmount时候取消监听。第二个应用场景State Provider,典型的例子就是 回到HOC,对于Lifecycle Hook而言,由于本身就返回一个新的ReactComponent,这一点毫无压力。对于State Provider而言,可以通过新的ReactComponent的state来维护。 但是: 两者在生命周期上有差异。这是我的测试结果,其中hoc表示HOC返回的新的ReactComponent,app表示的是WrappedComponent: hoc componentWillMount app componentWillMount app componentDidMount hoc componentDidMount 注:这里的componentWillMount是在constructor中输出的。 然后如果在HOC返回的新组件中更新状态的话: hoc componentWillUpdate app componentWillReceiveProps app componentWillUpdate app componentDidUpdate hoc componentDidUpdate 最后是unmount的部分: hoc componentWillUnmount app componentWillUnmount 大家自行和mixin比较下吧。其实得到这样的结果是很正常的,熟悉React父子组件之间生命周期关系的同学一定不会陌生。 暴露API的方式不同。在使用mixin时,通过会添加一个方法,比如 HOC实践如果大家用Redux的话,
@reactMixin.decorate(mixin) class AnotherComponent extends Component { ... } recompose这个库可以关注下,里面有大量的HOC实现可以尝试尝试,这个库我也刚接触,就不多展开了。 安利下我的react-async-script-loader,用来异步加载依赖脚本的HOC,可以关注下,欢迎提issue。 存在的问题这是我在实践中遇到的两个问题,可能之后会再更新: HOC导致内部ref丢失。在实践的时候,通常HOC都是“隐身”的,比如: // Editor.jsx @scriptLoader(...) class Editor extends Component { ... } export default Editor // -------------------------------------- // Form.jsx import Editor from './Editor.jsx' <Editor ref="editor" /> 这里的 解决办法是定义一个 componentWillReceiveProps失控。由于HOC返回的新组件是通过给子组件传递属性的方式来传递状态的改变的,那么如果应用过多的HOC的话,可能导致 最后,HOC由于并不是官方解决方案,遇到坑的原因主要也是缺乏一个统一的Convention,持续观望中,大家对HOC有任何看法的话,欢迎交流。 相关文章和资源https://github.com/acdlite/flummox/blob/v3.5.1/docs/docs/guides/why-flux-component-is-better-than-flux-mixin.md https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750#.trp9l55l0 https://github.com/facebook/react/issues/2669 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |