React--组件间抽象

本文探讨了在React组件开发中如何进行抽象,主要围绕mixin和高阶组件展开。介绍了mixin的概念、使用方法及其带来的问题,如命名冲突和增加组件复杂性。接着讨论了高阶组件,包括属性代理和反向继承两种实现方式,作为解决mixin问题的替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在React组件构建的过程中,常常会有一类功能需要不同的组件公用的情况。此时就涉及到了抽象的问题。

mixin

所谓Mixin,就是讲一个模块混入到另一个模块之中,或是一个类中。

事实上mixin就类似于多重继承

封装mixin方法

function mixin(obj, mixins){
    const newObj = obj;
    newObj.prototype = Object.create(obj.prototype);
    
    for(let prop in mixins){
        if(mixins.hasOwnProperty(prop)){
            newObj.prototype[prop] = mixins[prop];
        }
    }
    return newObj;
}

const bigMixin = {
    fly: ()=>{console.log('I can fly');}
}

const big = function(){
    console.log('new big');
}

const flyBig = mixin(big, bigMixin);

对于广义的mixin方法,就是用赋值的方式将mixin对象里的方法都挂载到原对象上。

在React中使用mixin

React在使用createClass构建组件是提供了mixin属性,比如官方封装的PureRenderMixin

import React from 'react';
import PureRenderMixin from 'react-addons-pure-render-mixin';

React.createClass({
    mixins: [PureRenderMixin]
    
    render(){
        return <div>foo</div>
    }
});

createClass对象参数中传入数组mixins,里面封装了我们所需要的模块。mixins数组也可以增加多个mixin,其每一个mixin方法之间若有重合,对于普通方法和生命周期方法是有所区分的。

在不同的mixin里实现两个名字一样的普通方法,按理说,后面的方法应该会覆盖前面的方法,但是在React中是不会覆盖的,而是会报一个ReactClassInterface的错误,指出你尝试在组件中多次定义一个方法。

可以看出,React中不允许出现重名普通方法的mixin

而如果是React的生命周期方法,则会将各个磨矿的生命周期方法叠加在一起顺序执行

mixin的问题

  • 破坏了原有组件的封装

mixin通过混入方法,为原有组件带来新的特性,但它也可能带来了新的stateprops,这意味着组件有一些“不可见”的状态需要我们去维护,但我们在使用的时候并不清楚。

另外,mixin也有可能去依赖其他的mixin,这样会建立一个mixin的依赖链。

命名冲突

不同的mixin中的命名在不可知的情况下重用是不可控的。

尽管可以通过更改名字来解决,但遇到第三方引用,或已经引用了几个mixin的情况下,总是要花一定的成本去解决冲突。

增加复杂性

引入一个mixin,就给组件引进了该mixin可能包含的生命周期方法,那么引入越多mixin,就有越多生命周期方法被引入组件,这样一来,组件的代码实现可能就复杂到难以维护。

高阶组件

可能我们更熟悉“高阶函数”这个概念,例如常见的mapreducesort都是高阶函数。它们接受函数作为输入,或者是用函数作为输出

那么同样的,高阶组件接受React组件作为输入,输出一个新的React组件。

实现高阶组件的方法有如下两种:

  • 属性代理
  • 反向继承

属性代理

属性代理是最常见的高阶组件的实现方法,例如:


const MyContainer = (WrappedComponent) => {
  return class extends Component{
    render(){
      const newProps = {
        text: 'this is new Props'
      }
      return <WrappedComponent {...this.props} {...newProps}/>;
    }
  }
}

class Controlled extends Component{
  constructor(props){
    super(props);
    console.log(props.text);
    this.changeHandle = this.changeHandle.bind(this);
  }

  changeHandle(e){
    emitter.emit('change', e.target.value);
  }

  render(){
    const {inputState} = this.props;
    return (
      <div>
        <input type='text' value={inputState} onChange={this.changeHandle}></input>
      </div>
    )
  }
}

const Test = MyContainer(Controlled);

此时Test就是一个React组件,在控制台中也能看到为Controlled组件添加的text prop

[外链图片转存失败(img-fxu1hVK4-1563110020318)(http://note.youdao.com/yws/res/16877/680548FCBECC4B1492D21C48CC602FA7)]

反向继承

const MyContainer = (WrappedComponent) => {
    return class extends WrappedComponent{
        render(){
            return super.render();
        }
    }
}

通过反向继承实现的高阶组件都是继承自WrappedComponent,因为继承了WrappedComponent所有的调用的会反向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值