06月19, 2017

js装饰器笔记

简单记录一下decorator这货。

它可以作用于类的装饰器,如:

function isAnimal(target) {
    target.isAnimal = true;
      return target;
}
@isAnimal
class Cat {
    ...
}
console.log(Cat.isAnimal);    // true

也可以作用于类属性的装饰器,如:

function readonly(target, name, descriptor) {
    descriptor.writable = false;
    return descriptor;
}
class Cat {
    @readonly
    say() {
        console.log("meow ~");
    }
}
var kitty = new Cat();
kitty.say = function() {
    console.log("woof !");
}
kitty.say()    // Error: Cannot assign to read only property 'say' of object '#<Cat>'

下面来看看,具体在项目中的实践。

React生命周期中并没有把onEnter/onLeave,(当然可能还会有onRefresh),给加进去,因为它只充当view。但是当我们使用react-route时,容器组件可能会用到上面的方法。比较常见的是编辑器页面离开的时候,要做判断,如未保存之类的。

这里我们可以参考一下其他人的写法,如A collection of higher-order ReactJS components

方案一

import React, { Component } from 'react';

import { withRouter } from 'react-router';

function pageDecorator({onEnter=() => {}, onLeave=() => {}}) {
    return function (ComposedComponent) {
        @withRouter
        class Page extends Component {
            componentDidMount() {
                onEnter.call(this);
                this.props.router.setRouteLeaveHook(
                    this.props.route,
                    () => {
                        onLeave.call(this);
                    }
                )
            }

            render() {
                return <ComposedComponent {...this.props} />;
            }
        };
        return Page;
    }

}

export default pageDecorator;

使用:

import pageDecorator from "DECORATOR/pageDecorator";

const mapStateToProps = (state){
       return {
        }
}

@connect(mapStateToProps)
@pageDecorator({
    onEnter: function () {
        this.props.dispatch(appDisabled(false));
    },
    onLeave: function (nextLocation) {
        this.props.dispatch(appDisabled(true));
    }
})
class ConfigListWrapper extends Component {
}

方案二

方案一,我个人觉得要传参,在没写onEnter/onLeave的情况下,倒是还好。。已经写了的话,还要将它提取出来,放到装饰器里面去,就显示略low了

那么现在要做的是取到ComposedComponent里面的onEnter方法。

在react es6 class里面,onEnter一般会有两种写法:

onEnter = () => {

}
onEnter () {
}

第一种是叫实例方法,第二种是叫类方法。相对之下,箭头函数会有更大的开销。

类方法,直接通过Funcion.prototype.onEnter即可取到。

import React, { Component } from 'react';

import { withRouter } from 'react-router';

function pageDecorator(ComposedComponent) {
    @withRouter
    class Page extends Component {
        componentDidMount() {
            let proto = ComposedComponent.prototype,
                onEnter = proto.onEnter,
                onLeave = proto.onLeave;
            onEnter && onEnter.call(this);
            this.props.router.setRouteLeaveHook(
                this.props.route,
                () => {
                    onLeave && onLeave.call(this);
                }
            )
        }

        render() {
            return <ComposedComponent {...this.props} />;
        }
    };
    return Page;
}

export default pageDecorator;

使用:

import pageDecorator from "DECORATOR/pageDecorator";

const mapStateToProps = (state){
       return {
        }
}

@connect(mapStateToProps)
@pageDecorator
class ConfigListWrapper extends Component {
      onEnter () {
         this.props.dispatch(appDisabled(false));
      }

      onLeave (nextLocation) {
         this.props.dispatch(appDisabled(true));
      }
}

方案三

类方法通过Function.prototype.onEnter可以拿到,那么实例方法呢?

我们可以这样来写:

class A {
    didMount() {
           this.subInstance ? this.subInstance.onEnter()
       }
       getRef = (ref) => {this.subInstance = ref};
       render() { 
             return <Sub ref={this.getRef}/>
       }
}

所以就可以写出下面的代码了:

import React, { Component } from 'react';

import { withRouter } from 'react-router';

function pageDecorator(ComposedComponent) {
    @withRouter
    class Page extends Component {
        componentDidMount() {
            let subIntance = this.subInstance,
                onEnter = subIntance.onEnter,
                onLeave = subIntance.onLeave;
            onEnter && onEnter.call(this);
            this.props.router.setRouteLeaveHook(
                this.props.route,
                () => {
                    onLeave && onLeave.call(this);
                }
            )
        }

        getRef = (ref) => {
            this.subInstance = ref;
        }

        render() {
            return <ComposedComponent ref={this.getRef} {...this.props} />;
        }
    };
    return Page;
}

export default pageDecorator;

使用:

import pageDecorator from "DECORATOR/pageDecorator";

const mapStateToProps = (state){
       return {
        }
}

@connect(mapStateToProps)
@pageDecorator
class ConfigListWrapper extends Component {
      onEnter = () => {
              this.props.dispatch(appDisabled(false));
      }

      onLeave = (nextLocation) => {
              this.props.dispatch(appDisabled(true));
      }
}

参考

本文链接:www.my-fe.pub/post/js-decorator.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。