react 高阶组件(HOC)的两种方式 与 HOC中ref的使用(react.forwardRef)

3,049 阅读2分钟

简单理解react的高阶组件其实就是定义一个函数。这个函数接收一个组件为参数,返回一个进行过封装,拓展的新的组件。

现在常用到的两种实现方式

1.属性代理

封装或者扩展传入的组件。为布局或者添加功能将传入组件进行包裹
  function HOC(WrappedComponent) {
    return class PP extends React.Component {
      render() {
        return (
          <div>
            <WrappedComponent {...this.props}/>
            <Modal/>
          </div>
        )
      }
    }
  }
添加新的props
function HOC(WrappedComponent) {
  return class PP extends React.Component {
    render() {
      const newProps = {
        name: 'zhangsan'
      }
      return <WrappedComponent {...this.props} {...newProps}/>
    }
  }
}

2.反向继承

高阶组件继承与传入的组件

HOC继承了WrappedComponent,意味着可以访问到WrappedComponent的state,props,生命周期和render方法。如果在HOC中定义了与WrappedComponent同名方法,将会发生覆盖,就必须手动通过super进行调用。通过完全操作WrappedComponent的render方法返回的元素树,可以真正实现渲染劫持。这种思想具有较强的入侵性。

function ppHOC(WrappedComponent) {
  return class ExampleEnhance extends WrappedComponent {
    ...
    componentDidMount() {
      super.componentDidMount();
    }
    componentWillUnmount() {
      super.componentWillUnmount();
    }
    render() {
      ...
      return super.render();
    }
  }
}

HOC中ref的使用(react.forwardRef)

当使用HOC后应为组件上边还有一层,ref取到的其实是hoc的实例,并不能拿到我们想要的。

react 16.3之前的做法是在hoc中定义this.childRef = React.createRef();

const HOC = function(WrappedComponent) {
	return class PP extends React.Component {
    	
        constructor(props) {
        	super(props);
            this.child = React.createRef();
        }
        
    	render() {
    		return <WrappedComponent ref={this.child} {...this.props}/>
        }
    }
}

@HOC
const ChildComponent = () => {
	return <div>hellow word</div>
}

class Com extends React.Component {
	constructor(props) {
        super(props);
        this.child = React.createRef();
    }
    
    componentDidMount() {
    	console.log(this.child.current.child);
    }
    render() {
        return <ChildComponent ref={this.child} {...this.props}/>
    }
}

react 16.3之后新增了React.forwardRef可以使ref直接透传到组件上,而不是HOC

// 使用forwardRef给纯函数组件包裹后使其拥有ref

const ChildComponent = React.forwardRef((props, ref) => (
	<button ref={ref}>
    	{this.props.children}
    </button>
)})

const ref = React.createRef();

<ChildComponent>chick me!</ChildComponent>

// HOC透传ref

function (Component) {
	class LogProps extends React.Component {
    	componentDidUpdate(prevProps) {
        	console.log('old props', prevProps);
            console.log('new props', this.props);
        }
        
        render() {
        	const {forwardRef, ...rest} = this.props;
            
            // Assign the custom prop 'forwardedRef' as a ref
            // 将自定义props “forwardedRef” 保存到ref上
            return <Component ref={forwardedRef} {...rest} />
        }
    }
    
    // Note the second param 'ref' provided by React.forwardRef.
    // 第二个参数由forwardRef提供的
    // We can pass it along to LogProps as regular prop. e.g. 'forwardedRef'
    // 将forwardedRef传给LogProps组件
    // And it can then be attached to Component.
    return React.forwardRef((props, ref) => {
    	return <LogProps {...props} forwardedRef={ref} />
    })
}

以上!