美文网首页
【React】—组件间抽象(mixin与高阶组件)

【React】—组件间抽象(mixin与高阶组件)

作者: 南慕瑶 | 来源:发表于2017-12-28 15:41 被阅读0次

    一、mixin

    什么是mixin:创造一种类似多重继承的效果。事实上,说它是组合更为贴切。

    1.封装mixin方法实例:

    const mixin = function(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); // new big

    const flyBig = new FlyBig(); // I can fly 

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

    2.在React中使用mixin

    React在使用createClass构建组件时提供了mixin属性。(ES6 classes形式构建组件时,不支持mixin)

    实例:

    import React from 'react';

    import PureRenderMixin from 'react-addons-pure-render-mixin'; //官方封装的mixin对象

    React.creatClass({
        mixins:[PureRenderMixin],

        reder(){

            return <div>foo</div>;

        }    
    });

    注:mixins属性可以指定多个mixin。但,如果两个mixin(也就是两个对象)中有名称相同的方法,会报命名冲突错误。

    使用createClass实现的mixin可以为组件做两件事:

    (1)定义工具方法。用mixin混入写好的工具方法。在需要用到工具方法的组件中设置mixin,即可使用相应工具方法。

    (2)生命周期继承,props、state的合并。如果多个mixin对象中,都定义了同一个生命周期,react会智能地将它们合并起来执行。

    3.ES6 Classes 与 decorator

    es6 classes语法,用decorator实现mixin。

    注:decorator与Java中pre-defined annotation的区别是,decorator是运用在运行时的方法。

    4.mixin存在的问题

    (1)破坏了原有组件的封装。

        mixin中的方法会带来新的state和props,及其他未知操作,在使用组件中不可知,无法有目的地控制。

    (2)命名冲突。

        多个mixin中,或mixin与当前组件,可能存在相同命名的方法,从而命名冲突。

    (3)增加复杂性。

        当添加了越来越多的mixin,就会引入越来越多的方法,从而造成代码逻辑复杂,不易维护。

    二、高阶组件

    1.高阶函数:

    概念:接受函数作为输入,或是输出一个函数,的函数。

    如常用的map、reduce、sort等,都是高阶函数。

    2.高阶组件

    概念:类似于高阶函数。接受React组件作为输入,输出一个新的React组件。

    实现方法:

    (1)属性代理:高阶组件通过被包裹的React组件来操作props。

    定义高阶组件:

    import React,{Component} from 'React';

    const MyContainer = (WrappedComponent) =>

        class extends Component {

            render() {

                return <WrappedComponent {...this.props} />;

            }

        }

    高阶组件:MyContainer

    被包裹组件:WrappedComponent

    {...this.props}是WrappedComponent的props对象。除了原封不动传递WrappedComponent的props,在高阶组件中,可以设置其他props,并传递给WrappedComponent。例如:

    import React,{Component} from 'React';

    const MyContainer = (WrappedComponent) =>   

        class extends Component {       

            render() { 

                 const newProps = {

                     text:newText,       

                 };         

                return  <WrappedComponent {...this.props} {...newProps} />;    

     //注:this.props读取的是,调用WrappedComponent时传入的props。注意{...this.props}和{...newProps}书写的先后顺序。如果this.props和newProps中有相同的prop,后面的会覆盖前面的。

         }   

     }

    对于WrappedComponent来说,只要套用这个高阶组件,我们的新组件中就会多一个text的prop。

    使用高阶组件:

    import React,{Component} from 'React';

    class MyComponent extends Component{

        //......

    }

    export default MyContainer(MyComponent);

    import React,{Component} from 'React';

    @MyContainer

    class MyComponent extends Component{   

        render(){ }

    }

    export default MyComponent;

    生命周期执行过程(类似于堆栈调用):

    didmount -> HOC didmount -> (HOCs didmount) -> 

    (HOCs will unmount) -> HOC will unmount -> unmount

    (2)反向继承:高阶组件继承于被包裹的React组件。

    定义高阶组件:

    const MyContainer = (WrappedComponent) =>

        class extends WrappedComponent {

            render(){

                return super.render();

            }

        }

    HOC调用顺序(类似于队列):

    didmount -> HOC didmount => (HOCs didmount) -> 

    will unmount -> HOC will unmount -> (HOCs will unmount)

    渲染劫持示例:

    NO1:条件渲染

    const MyContainer = (WrappedComponent) =>

        class extends WrappedComponent {

            render(){

                if(this.props.loggedIn){

                    return super.render();

                }else{

                    return null;

                }

            }

        }

    NO2:修改render输出结果

    const MyContainer = (WrappedComponent) =>

        class extends WrappedComponent {

            render(){

                const elementsTree = super.render();

                let newProps = {};

                if(elementsTree && elementsTree.type === 'input'){

                    newProps = {value:'may the force be with you'};

                }

                const props = Object.assign({},elementsTree.props,newProps);

                const newElementsTree =                 React.cloneElement(elementsTree,props,elementsTree.props.children);

                return newElementsTree;

            }

        }

    相关文章

      网友评论

          本文标题:【React】—组件间抽象(mixin与高阶组件)

          本文链接:https://www.haomeiwen.com/subject/nydtgxtx.html