You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
classExampleextendsReact.PureComponent{constructor(props){super(props);this.consoleFun.bind(this);}consoleFun(){console.log("hello world");}render(){const{ age }=this.props;return(<div><p>{age}</p></div>);}}functionHOC(WrappedComponent){classEnhancedComponentextendsReact.PureComponent{initFunc(instance){instance.consoleFun();}render(){constprops=Object.assign({},this.props,{ref: this.initFunc.bind(this)});return<WrappedComponent{...props}/>;}}returnEnhancedComponent;}constHocComponent=HOC(Example);ReactDom.render(<HocComponentage={24}/>,document.getElementById("root"));
如果想要在 HOC 中执行被包裹组件的一些方法,就可以在 props 上组装一下 ref 这个属性,就可以获取到被包裹组件的实例,从而获取到实例的 props 以及它的方法。
反向继承是指 HOC 继承被包裹组件,这样被包裹的组件 (WrappedComponent) 就是 HOC 的父组件了,子组件就可以直接操作父组件的所有公开的方法和字段。
反向继承可以实现如下功能:
对 WrappedComponent 的所有生命周期函数进行重写,或者修改其 props 或者 state
classExampleextendsReact.PureComponent{constructor(props){super(props);}componentDidMount(){console.log("wrappedComponent did mount");}render(){const{ age }=this.props;return(<div><p>{age}</p></div>);}}functionHOC(WrapperComponent){returnclassInheritanceextendsWrapperComponent{componentDidMount(){console.log("HOC did mount");super.componentDidMount();}render(){returnsuper.render();}};}constHocComponent=HOC(Example);ReactDom.render(<HocComponentage={24}/>,document.getElementById("root"));// HOC did mount// wrappedComponent did mount
classExampleextendsReact.PureComponent{constructor(props){super(props);}render(){const{ age }=this.props;return<input/>;}}functionHOC(WrapperComponent){returnclassInheritanceextendsWrapperComponent{render(){constelementsTree=super.render();letnewProps={};if(elementsTree&&elementsTree.type==="input"){newProps={defaultValue: "the initialValue of input"};}constprops=Object.assign({},elementsTree.props,newProps);constnewElementsTree=React.cloneElement(elementsTree,props,elementsTree.props.children);returnnewElementsTree;}};}constHocComponent=HOC(Example);ReactDom.render(<HocComponentage={24}/>,document.getElementById("root"));
运行如上代码,就可以得到一个默认值为 the initialValue of input 的 input 标签。因为 HOC 在 render 之前获取了 WrappedComponent 的 Dom 结构,从而可以自定义一些自己的东西,然后再执行本身的渲染操作。
HOC 的功能虽然很强大,但是在使用过程中还是需要注意,React 官方给出了一些注意事项,在此不赘述~
在谈及高阶组件之前,我们先来讲讲它的前身 mixin ~
mixin 的作用是:如果多个组件中包含相同的方法(包括普通函数和组件生命周期函数),就可以把这一类函数提取到 mixin 中,然后在需要公共方法的组件中使用 mixin, 就可以避免每个组件都去声明一次,从而达到复用。
React 在早期是使用 createClass 来创建一个 Component 的,而且 createClass 支持 mixin 属性,最常见的就是 react-addons-pure-render-mixin 库提供的 PureRenderMixin 方法,用来减少组件使用中一些不必要的渲染,使用方式如下:
和需要在每一个组件中都重复实现一遍 PureRenderMixin 中浅比较的逻辑相比,上面 mixin 中的使用显得更加简便和明了,同时减少了代码的冗余和重复。
minin 既可以定义多个组件中共享的工具方法,同时还可以定义一些组件的生命周期函数(例如上例的 shouldComponentUpdate), 以及初始的 props 和 states。
如下所示:
但是在使用 mixin 的时候,会有如下的几点需要注意:
不同 mixin 中有相同的函数
不同 mixin 中设置 props 或者 states
附上具体示例代码地址
虽然 mixin 在一定程度上解决了 React 实践中的一些痛点,但是 React 从 v0.13.0 开始,ES6 class 组件写法中不支持 mixins, 但是还是可以使用 createClass 来使用 mixin。之后,React 社区提出了一种新的方式来取代 mixin,那就是高阶组件 Higher-Order Components。
高阶组件
高阶组件 (Higher-Order Components) 是接受一个组件作为参数,然后经过一些处理,返回一个相对增强的组件的函数。它是 React 中的一种模式,而不是 API 的一部分。React 官方给出一个公式描述如下:
一个最简单的 HOC 例子如下:
高阶组件的适用场景
它的使用场景有如下几点:
高阶组件的实现方式
高阶组件有两种实现方式: 属性代理 (Props Proxy) 和反向继承 (Inheritance Inversion)
属性代理
属性代理是指所有的数据都是从最外层的 HOC 中传给被包裹的组件,它有权限对传入的数据进行修改,对于被包裹组件来说,HOC 对传给自己的属性 (Props) 起到了一层代理作用。
属性代理可以实现如下一些功能:
如上面的例子中,HOC 对最外层传入的 props 进行了二次组装,扩展了 props 的数据能力。
如果想要在 HOC 中执行被包裹组件的一些方法,就可以在 props 上组装一下 ref 这个属性,就可以获取到被包裹组件的实例,从而获取到实例的 props 以及它的方法。
这个比较简单,不详述~
反向继承 (Inheritance Inversion)
反向继承是指 HOC 继承被包裹组件,这样被包裹的组件 (WrappedComponent) 就是 HOC 的父组件了,子组件就可以直接操作父组件的所有公开的方法和字段。
反向继承可以实现如下功能:
由上面可以看到,HOC 中定义的生命周期方法可以访问到 WrappedComponent 中的生命周期方法。两者的执行顺序由代码的执行顺序决定。
运行如上代码,就可以得到一个默认值为 the initialValue of input 的 input 标签。因为 HOC 在 render 之前获取了 WrappedComponent 的 Dom 结构,从而可以自定义一些自己的东西,然后再执行本身的渲染操作。
HOC 的功能虽然很强大,但是在使用过程中还是需要注意,React 官方给出了一些注意事项,在此不赘述~
附上具体示例代码地址
mixin VS HOC
mixin 和 HOC 都能解决代码复用的问题,但是 mixin 存在如下缺点:
除了上面的显著缺点外,还有一些其他的,详见 Mixins Considered Harmful
而且 HOC 更接近于函数式编程的思想,在使用上也更加灵活,包括的功能点也更多。一张图可以很形象地表达出两者的区别:
总结
虽然在 React 实践中,选择实现的方式有很多种,但是为了考虑可维护性和扩展性,还是推荐使用 HOC 的方式。目前暂无很深刻的实践经验,这篇只是纯理论知识+一些简单的 demo,后续会持续踩坑~
参考文章
The text was updated successfully, but these errors were encountered: