1、react高阶组件
参数为一个组件,返回一个新的组件
2、代理方式的高阶组件: 特点是 返回的组件直接继承自 React.Component,应用场景为:
1)、操纵props
可以增加,删除,修改传入组件的props
1 const addNewProps = (WrappedComponent, newProps) => { 2 return class WrappingComponent extends React.Component { 3 render() { 4 return <WrappedComponent {...this.props} {...newProps} /> 5 } 6 } 7 }
2)、访问ref
直接访问ref违背远离DOM的原则,可以通过在高阶组件中增加一层控制来代替ref,其实也是通过增加prop的方法,利用ref的值是函数时参数就是这个组件的DOM元素
const refsHOC = (WrappedComponent) => { return class HOCComponent extends React.Component { constructor() { super(...arguments); this.linkRef = this.linkRef.bind(this); } linkRef(wrappedInstance) { this._root = wrappedInstance; } render() { const props = {...this.props, ref: this.linkRef}; return <WrappedComponent {...props}/>; } }; };
3)、抽取状态
为传入的组件提供一个容器组件来管理状态,类似于connect 函数执行完返回的函数。
connect为传入的组件提供了redux的获取,状态变化监听等状态管理
const doNothing = () => ({}); function connect(mapStateToProps=doNothing, mapDispatchToProps=doNothing) { function getDisplayName(WrappedComponent) { return WrappedComponent.displayName || WrappedComponent.name || 'Component'; } return function(WrappedComponent) { class HOCComponent extends React.Component { constructor() { super(...arguments); this.onChange = this.onChange.bind(this); this.store = {}; } shouldComponentUpdate(nextProps, nextState) { for (const propType in nextProps) { if (nextProps.hasOwnProperty(propType)) { if (nextProps[propType] === this.props[propType]) { return true; } } } for (const propType in this.props) { if (this.props.hasOwnProperty(propType)) { if (nextProps[propType] === this.props[propType]) { return true; } } } return false; } componentDidMount() { this.context.store.subscribe(this.onChange); } componentWillUnmount() { this.context.store.unsubscribe(this.onChange); } onChange() { this.setState({}); } render() { const store = this.context.store; const newProps = { ...this.props, ...mapStateToProps(store.getState(), this.props), ...mapDispatchToProps(store.dispatch, this.props) } return <WrappedComponent {...newProps} />; } }; HOCComponent.contextTypes = { store: React.PropTypes.object } HOCComponent.displayName = `Connect(${getDisplayName(WrappedComponent)})`; return HOCComponent; }; }
4)、包装组件
在返回的新组件的render函数中引入其他元素或组合多个react组件等。为传入的组件做包装。
3、继承方式的高阶组件
特点: 继承传入的组件
在render 函数中,获取传入组件的JSX代码需要使用super.render,改变传入组件的props要为this.props赋值(这样做其实违背了render是纯函数的原则,改变props是方法之一,另一种方法是利用React.cloneElement让组件重新绘制),经历的生命周期也是一个生命周期(代理方式是两个组件,相应的,也是两个生命周期),应用场景为:
1)、操纵props
因为React.cloneElement实现的方式太复杂,所以这样的方式一般用于根据传入组件的渲染结果进行判断来决定如何修改props的场景。
const modifyPropsHOC = (WrappedComponent) => { return class NewComponent extends WrappedComponent { render() { const elements = super.render(); const newStyle = { color: (elements && elements.type === 'div') ? 'red' : 'green' } const newProps = {...this.props, style: newStyle}; return React.cloneElement(elements, newProps, elements.props.children); } }; };
2)、操纵生命周期函数
重写父组件的生命周期函数
参考:深入浅出react和redux(程墨)