All files / i-react-utils/src LazyLoad.js

82.5% Statements 33/40
73.33% Branches 11/15
80% Functions 8/10
82.05% Lines 32/39
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          6x 6x 6x                                   4x 4x 4x 4x 4x 4x       4x 1x   3x 3x 2x 1x 1x 1x 1x 1x     1x 1x 1x 1x 1x 1x           1x                   4x                     4x 4x 2x 2x         2x          
import React from 'react';
import {devOnly, shallowCopyExcept} from 'i-js-utils';
import {_buildElement} from './utils-internal';
 
function _subElementProps(source) {
    let dst = {};
    shallowCopyExcept(dst, source, ['component', 'errorComponent', 'loadingComponent', 'ajax']);
    return dst;
}
 
export default class LazyLoad extends React.Component {
 
    static propTypes = {
        component : React.PropTypes.oneOfType([ React.PropTypes.func, React.PropTypes.element ]).isRequired,
        errorComponent : React.PropTypes.oneOfType([ React.PropTypes.func, React.PropTypes.element ]),          // component function or element
        loadingComponent : React.PropTypes.oneOfType([ React.PropTypes.func, React.PropTypes.element ]),        // component function or element
        ajax : React.PropTypes.func.isRequired                                                                  // function that returns Ajax Promise
    };
 
    static defaultProps = {
        errorComponent : null,
        loadingComponent : null
    };
 
    constructor(props) {
        super();
        this.state = { element : null, loading : true };
        this._setup = this._setup.bind(this);
        this.reload = this.reload.bind(this);
        this.subElementProps = _subElementProps(props);
        this.loadingElement = _buildElement(props.loadingComponent, this.subElementProps, []);
    }
 
    _setup(props) {
        if (props.component == undefined) {
            throw new Error('Property component of LazyLoad is required');
        }
        let promise = props.ajax();
        if (promise && promise.then && promise.catch) {
            promise.then((res) => {
                let data = res.data;
                const cProps = _subElementProps(props);
                cProps.data = data;
                const element = _buildElement(props.component, cProps, props.children);
                this.setState({element: element, loading: false});
            })
            .catch((err) => {
                devOnly(() => {console.log('Unable to load resource via ajax for LazyLoad.', err);});
                Eif (props.errorComponent) {
                    const cProps = _subElementProps(props);
                    cProps.data = err.response.data;
                    const element = _buildElement(props.errorComponent, cProps, props.children);
                    this.setState({element: element, loading: false});
                } else {
                    this.setState({element: null, loading: false});
                }
            });
        } else {
            throw new Error('Ajax returned ' + promise + ' instead of Promise.');
        }
    }
 
    reload() {
        this.setState({ element : null, loading : true });
        this._setup(this.props);
    }
 
    componentWillMount() {
        this._setup(this.props);
    }
 
    componentWillReceiveProps(newProps) {
        if (this.props.loadingComponent != newProps.loadingComponent) {
            this.loadingElement = _buildElement(newProps.loadingComponent, _subElementProps(newProps), []);
        }
        this.props = newProps;
    }
 
    render() {
        const {element, loading} = this.state;
        if (element == null) {
            Eif (loading) {
                return this.loadingElement;
            } else {
                return null;
            }
        } else {
            return element;
        }
    }
 
}