-
Container解决不了的时候甚至不太优雅的时候。其实大部分时候包一层Container组件也能做到差不多的效果,比如操作props,渲染劫持。但其实还是有很大区别的。比如我们现在有两个功能的container,添加样式和添加处理函数的,对Usual进行包装。栗子:
//usual class Usual extends Component { render() { console.log(this.props, ‘props‘); return <div> Usual </div> } }; export default Usual; //console - Object {handleClick: function} "props"
import React, { Component } from ‘react‘; import Usual from ‘./usual‘; class StyleContainer extends Component { render() { return (<div style={{ color: ‘#76d0a3‘ }}> <div>container</div> <Usual {...this.props} /> </div>); } } export default StyleContainer;
import React, { Component } from ‘react‘; import StyleContainer from ‘./container-add-style‘; class FuncContainer extends Component { handleClick() { console.log(‘click‘); } render() { const props = { ...this.props, handleClick: this.handleClick, }; return (<StyleContainer {...props} />); } } export default FuncContainer;
外层Container必须要引入内层Container,进行包装,还有props的传递,同样要注意包装的顺序。当然你可以把所有的处理都放到一个Container里。那用HOC怎么处理呢,相信大家有清晰的答案了。
const addFunc = WrappedComponent => class extends Component { handleClick() { console.log(‘click‘); } render() { const props = { ...this.props, handleClick: this.handleClick, }; return <WrappedComponent {...props} />; } };
const addStyle = WrappedComponent => class extends Component { render() { return (<div style={{ color: ‘#76d0a3‘ }}> <WrappedComponent {...this.props} /> </div>); } };
const WrappenComponent = addStyle(addFunc(Usual)); class WrappedUsual extends Component { render() { console.log(this.props, ‘props‘); return (<div> <WrappedComponent /> </div>); } }
显然HOC是更优雅一些的,每个HOC都定义自己独有的处理逻辑,需要的时候只需要去包装你的组件。相较于Container的方式,HOC耦合性更低,灵活性更高,可以自由组合,更适合应付复杂的业务。当然当你的需求很简单的时候,还是用Container去自由组合,应用场景需要你清楚。
注意点(约束)
其实官网有很多,简单介绍一下。
- 最重要的原则就是,注意高阶组件不会修改子组件,也不拷贝子组件的行为。高阶组件只是通过组合的方式将子组件包装在容器组件中,是一个无副作用的纯函数
-
要给hoc添加class名,便于debugger。我上面的好多栗子组件都没写class 名,请不要学我,因为我实在想不出叫什么名了... 当我们在chrome里应用React-Developer-Tools的时候,组件结构可以一目了然,所以DisplayName最好还是加上。
-
静态方法要复制
无论PP还是II的方式,WrappedComponent的静态方法都不会复制,如果要用需要我们单独复制。 -
refs不会传递。 意思就是HOC里指定的ref,并不会传递到子组件,如果你要使用最好写回调函数通过props传下去。
-
不要在render方法内部使用高阶组件。简单来说react的差分算法会去比较 NowElement === OldElement, 来决定要不要替换这个elementTree。也就是如果你每次返回的结果都不是一个引用,react以为发生了变化,去更替这个组件会导致之前组件的状态丢失。
// HOC不要放到render函数里面 class WrappedUsual extends Component { render() { const WrappenComponent = addStyle(addFunc(Usual)); console.log(this.props, ‘props‘); return (<div> <WrappedComponent /> </div>); } }
-
使用compose组合HOC。函数式编程的套路... 例如应用redux中的middleware以增强功能。redux-middleware解析
const addFuncHOC = ... const addStyleHOC = ...//省略 const compose = (...funcs) => component => { if (funcs.lenght === 0) { return component; } const last = funcs[funcs.length - 1]; return funcs.reduceRight((res, cur) => cur(res), last(component)); }; const WrappedComponent = compose(addFuncHOC, addStyleHOC)(Usual);
关于注意点,官网有所介绍,不再赘述。链接
总结
高阶组件最大的好处就是解耦和灵活性,在react的开发中还是很有用的。
当然这不可能是高阶组件的全部用法。掌握了它的一些技巧,还有一些限制,你可以结合你的应用场景,发散思维,尝试一些不同的用法。