Dependency Injection / Higher-Order Component (HOC)

Dependency Injection / Higher-Order Component (HOC)

Dependency injection is a useful technique to get your dependency only when u need.

Example dependency structure

import React from 'react';

function buildComponent(
    WrappedComponent, 
    decorator = '',
) {
    return class extends React.Component {
        render() {
            const newProps = Object.assign({
                [decorator]: {

                }
            }, this.props);

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

export default injector(buildComponent);

Utility function ( injector & compose )

export const injector = (build) => {
    return function () {
        const decorators = arguments;
        return typeof arguments[0] !== 'string'
            ? build(...decorators)
            : function (WrappedComponent) {
                return build(WrappedComponent, ...decorators);
            };
    };
};

export const compose = (...enhancers) => {
    return (WrappedComponent) => {
        let Component = WrappedComponent;
        for (const enhancer of enhancers) {
            Component = enhancer(Component);
        }
        return Component;
    };
};

Example with apisauce and digital ocean API

Dependency

import React from 'react';
import { create } from 'apisauce';
import { injector } from 'utility';

const axios = create({ 
    baseURL: 'https://api.digitalocean.com/v2', 
    headers: {
        'Authorization': `Bearer ${API_KEY}`,
        'Content-Type': 'application/json',
    },
    timeout: 30000
});

function buildComponent(
    WrappedComponent, 
    decorator = 'do',
) {
    return class extends React.Component {
        render() {
            const newProps = Object.assign({
                [decorator]: {
                    getDroplets: async () => {
                        const response = await axios.get('/droplets');
                        if (response.data) {
                            return response.data.droplets;
                        }
                    },
                }
            }, this.props);

            return (
                <WrappedComponent
                    {...newProps}
                />
            );
        }
    };
};

export default injector(buildComponent);

Component

import React from 'react';
import withDO from 'doapi';
import { compose } from 'utility';

export class Component extends React.Component {
    state = {
        droplets: null,
    }

    componentDidMount() {
        this.props.do.getDroplets()
            .then(
                (droplets) => this.setState({ droplets })
            )
            .catch(console.error);
    }

    render() {
        return (
            <div>
            </div>
        );
    }
};

export default compose(
    withDO
    // You can specify inject name also by withDO('api')
    // If no specify will inject default name that you have set.
)(Component);