appbaseio/reactivesearch

View on GitHub
packages/vue/src/utils/connector.js

Summary

Maintainability
A
1 hr
Test Coverage
import { bindActionCreators } from 'redux';
import shallowEqual from './shallowEqual';

const defaultMapState = () => ({});
const defaultMapDispatch = {};

const normalizeMapState = mapState => {
    if (typeof mapState === 'function') return mapState;

    if (mapState === Object(mapState)) {
        return (state, ownProps) =>
            Object.keys(mapState)
                .filter(key => typeof mapState[key] === 'function')
                .reduce(
                    (map, key) => ({ ...map, [key]: mapState[key](state, ownProps) }),
                    {}
                );
    }

    throw new Error('[revux] - mapState provided to connect is invalid');
};

// eslint-disable-next-line
const connector = (
    _mapState = defaultMapState,
    mapDispatch = defaultMapDispatch
) => component => {
    const mapState = normalizeMapState(_mapState);

    return {
        name: `connect-${component.name}`,
        mixins: [component],
        inject: ['$$store'],

        data() {
            const merged = {
                ...mapState(this.$$store.getState(), this.$props || {}),
                ...bindActionCreators(mapDispatch, this.$$store.dispatch)
            };

            return Object.keys(merged).reduce(
                (data, key) => ({ ...data, [key]: merged[key] }),
                {}
            );
        },

        created() {
            const getMappedState = state => mapState(state, this.$props || {});

            const observeStore = (store, select, onChange) => {
                let currentState = select(store.getState());

                return store.subscribe(() => {
                    const nextState = select(store.getState());
                    if (!shallowEqual(currentState, nextState)) {
                        const previousState = currentState;
                        currentState = nextState;
                        onChange(currentState, previousState);
                    }
                });
            };

            this._unsubscribe = observeStore(
                this.$$store,
                getMappedState,
                newState => {
                    Object.keys(newState).forEach(key => {
                        this.$set(this, key, newState[key]);
                    });
                }
            );
        },

        beforeDestroy() {
            this._unsubscribe();
        }
    };
};

export default connector;