React-高阶组件

参考博客(高阶组件):https://blog.youkuaiyun.com/sinat_17775997/article/details/100761756

高阶函数:如果一个函数 接受一个或多个函数作为参数或者返回一个函数 就可称之为 高阶函数


function withGreeting(greeting = () => {}) {
    return greeting;
}

高阶组件:如果一个函数 接受一个或多个组件作为参数并且返回一个组件 就可称之为 高阶组件

当高阶组件中返回的组件是 无状态组件(Stateless Component) 时,该高阶组件其实就是一个高阶函数,因为无状态组件 本身就是一个纯函数。

function HigherOrderComponent1(WrappedComponent) {
  return <WrappedComponent / >
}

有状态高阶组件:

function HigherOrderComponent2(WrappedComponent) {
  return class extends React.Component{
    render() {
      return <WrappedComponent {...this.props} />;
    }
  }
}

实现高阶组件的方法:属性代理(Props Proxy)和 反向继承(Inheritance Inversion); 

属性代理(Props Proxy)类型的高阶组件中可以做什么,比如:

  • 操作 props
  • 抽离 state
  • 通过 ref 访问到组件实例
  • 用其他元素包裹传入的组件 WrappedComponent

①操作 props

function HigherOrderComponent(WrappedComponent) {
    return class extends Component {
        constructor(props){
            supre(props);
            this.state = {};
        }
        render() {
            const newProps = {
                name: '大板栗',
                age: 18,
            };
            // console.log(this.props);
            return <WrappedComponent {...this.props} {...newProps} />;
        }
    };
}
export default HigherOrderComponent;

②抽离 state

function HigherOrderComponent(WrappedComponent) {
    return class extends Component {
        constructor(props){
            super(props);
            this.state = {
                name: ""
            };
        }
        render() {
            const newProps = {
                name:{
                    value: this.state.name,
                    onChange: this.onChange,
                }
            };
            // console.log(this.props);
            return <WrappedComponent {...this.props} {...newProps} />;
        }
        onChange = (name) => {
            this.setState({
                name: name,
            });
        }
    };
}
export default HigherOrderComponent;

③通过 ref 访问到组件实例

function HigherOrderComponent(WrappedComponent) {
    return class extends React.Component {
        render() {
            return <WrappedComponent {...this.props} ref={this.Method} />;
        }
        // ref 的值可以是字符串(不推荐使用)也可以是一个回调函数,如果是回调函数的话,它的执行时机是:
        // 组件被挂载后(componentDidMount),回调函数立即执行,回调函数的参数为该组件的实例。
        // 组件被卸载(componentDidUnmount)或者原有的 ref 属性本身发生变化的时候,此时回调函数也会立即执行,且回调函数的参数为 null
        Method = (instance) => {
            // wrappedComponentInstance.someMethod();
            console.log("我被调用了:");
            console.log(instance);
            // instance.test();
            console.log(instance.box.current);
        }
    };
}
export default HigherOrderComponent;

④用其他元素包裹传入的组件 WrappedComponent

function HigherOrderComponent(WrappedComponent){
    return class extends React.Component {
        render(){
            return (
                <div>
                    <h1>欢迎来到高阶组件</h1>
                    <WrappedComponent />
                </div>
            )
        }
    }
}
export default HigherOrderComponent;

模仿redux中的connect:

function connect(cb){
    return (WrappedComponent)=>{
        return class extends React.Component{
            render(){
                let obj = cb();
                // console.log(obj);
                return <WrappedComponent {...this.props} {...obj} />
            }
        }
    }
}
export default connect;

调用connect: 

export default connect(()=>{
  return{
    name:"张三",
    age: 18
  }
})(App);

反向继承(Inheritance Inversion)

最简单的反向继承实现:

function HigherOrderComponent(WrappedComponent) {
    return class extends WrappedComponent {
        render() {
            return super.render();
        }
    };
}

反向继承其实就是 一个函数接受一个 WrappedComponent 组件作为参数传入,并返回一个继承了该传入 WrappedComponent 组件的类,且在该类的 render() 方法中返回 super.render() 方法。

会发现其属性代理和反向继承的实现有些类似的地方,都是返回一个继承了某个父类的子类,只不过属性代理中继承的是 React.Component,反向继承中继承的是传入的组件 WrappedComponent。

反向继承可以用来做什么:

  • 操作 state
  • 渲染劫持(Render Highjacking)

①操作 state

高阶组件中可以读取、编辑和删除 WrappedComponent 组件实例中的 state。甚至可以增加更多的 state 项,但是 非常不建议这么做因为这可能会导致 state 难以维护及管理。

②渲染劫持(Render Highjacking)

之所以称之为 渲染劫持 是因为高阶组件控制着 WrappedComponent 组件的渲染输出,通过渲染劫持我们可以:

  • 有条件地展示元素树(element tree)
  • 操作由 render() 输出的 React 元素树
  • 在任何由 render() 输出的 React 元素中操作 props
  • 用其他元素包裹传入的组件 WrappedComponent (同 属性代理)

高阶组件的约定

高阶组件带给我们极大方便的同时,我们也要遵循一些约定:

  • props 保持一致
  • 你不能在函数式(无状态)组件上使用 ref 属性,因为它没有实例
  • 不要以任何方式改变原始组件 WrappedComponent
  • 透传不相关 props 属性给被包裹的组件 WrappedComponent
  • 不要再 render() 方法中使用高阶组件
  • 使用 compose 组合高阶组件
  • 包装显示名字以便于调试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值