All files react-observer.ts

79.55% Statements 35/44
70% Branches 14/20
80% Functions 8/10
79.55% Lines 35/44

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108  6x               6x 6x 6x 6x 6x 6x   11x     4x 7x 7x     4x 4x   6x   4x 4x 4x               8x 8x 8x 8x                                 3x   9x                   7x   7x 4x 4x 4x 4x   3x   6x   2x 2x   2x   6x                                      
/*
 * @Author: lijianzhang
 * @Date: 2018-03-31 21:40:26
 * @Last Modified by: lijianzhang
 * @Last Modified time: 2018-08-29 23:50:29
 * @flow
 */
import * as React from 'react';
import { SFC } from 'react';
import Observer from './observer';
import { OBSERVER_COMPONENT_KEY } from './constant';
 
const baseRenderKey = Symbol('baseRender');
const connectKey = Symbol('connect');
const $componentWillMount = Symbol('componentWillMount');
 
type IReactComponent<P = any> =
    | React.StatelessComponent<P>
    | React.ComponentClass<P>
    | React.ClassicComponentClass<P>;
E
function reactiveRender(this: React.Component) {
    return this[OBSERVER_COMPONENT_KEY].collectDep(this[baseRenderKey]);
}
 
function initRender(this: React.Component) {
    this[OBSERVER_COMPONENT_KEY] = new Observer(() => {
        if (this[$componentWillMount]) {
            this.forceUpdate();
        }
    }, `${this.constructor.name}.render()`);
 
    this.render = reactiveRender;
    return reactiveRender.call(this);
}

const reactiveMixin = {
    componentWillMount(this: React.Component) {
        this[$componentWillMount] = true;
        this[baseRenderKey] = this.render.bind(this);
        this.render = initRender;
    E},
 
    componentWillUnmount(this: React.Component) {
        this[OBSERVER_COMPONENT_KEY].unSubscribe();
        this[OBSERVER_COMPONENT_KEY] = null;
    },
};

function patch(target, funcName, runMixinFirst = false) {
    const base = target[funcName];
    const mixinFunc = reactiveMixin[funcName];
    if (!base) {
        target[funcName] = mixinFunc;
    } else {
        target[funcName] =
            runMixinFirst === true ?
                function funcName(this: React.Component, ...args) {
                    mixinFunc.apply(this, args);
                    base.apply(this, args);
                } :
                function funcName(this: React.Component, ...args) {
                    base.apply(this, args);
                    mixinFunc.apply(this, args);
                };
    }
}
 
 
function createObserverComponent(component: IReactComponent) {
    return class extends React.Component {
    I    static displayName = component.displayName || component.name;
        static propTypes = component.propTypes;
        static contextTypes = component.contextTypes;
        static defaultProps = component.defaultProps;
 
        render() {
            return component.call(this, this.props, this.context);
        }
    };
}
 
 
export default function ReactObserver<T extends IReactComponent>(target: T | SFC): T {
    Iif (target[connectKey]) return (target as T);
    if ( typeof target === "function" && (target.prototype && target.prototype.render) ) {
        target[connectKey] = true;
        patch(target.prototype, 'componentWillMount', true);
        patch(target.prototype, 'componentWillUnmount');
        return (target as T);
    }
 
    return ReactObserver(createObserverComponent(target as IReactComponent)) as any;
    
}
 
interface Props {
    children?: SFC | React.Factory<any> ;
    render?: SFC;
}
 
export function ObserverComponent(target: Props) {
 
    let Component = target.children || target.render;
    if (!Component) return null;
    return React.createElement(ReactObserver(Component));
}