UNPKG

react-loader-factory-immutable

Version:

A factory for creating custom functional react loading screen components (immutableJS version).

111 lines (97 loc) 3.29 kB
import React from 'react'; import { connect } from 'react-redux'; import equal from 'deep-equal'; function deepIncludes(arr, item) { return arr.some(el => equal(el, item)); } function shallowDesymbolize(obj) { if (obj instanceof Array) { return obj.map((el) => shallowDesymbolize(el)); } else if (obj instanceof Object) { const res = {}; Object.getOwnPropertySymbols(obj).forEach((key) => { const desymbolizedKey = ('__dsym__').concat(String(key)); res[desymbolizedKey] = obj[key]; }); return res; } return obj; } export default function loaderFactory(actionsList, requestStates, stateInjector, stateMonitor) { if (stateMonitor === undefined) { stateMonitor = function() { return false; }; } return function(WrappedComponent) { const factoryInjector = stateInjector || function(state) { return { activeRequests: state.get('activeRequests').toJS() }; }; const waitInjector = function(state) { return Object.assign(factoryInjector(state), { waitingOnStore: stateMonitor(state) }); }; class Loader extends React.Component { constructor(props) { super(props); this.currentRequests = []; this.needsDispatch = true; } render() { const { activeRequests, dispatch } = this.props; // monitor given request states const requestsBusy = this.needsDispatch || this.props.waitingOnStore || (function() { if (activeRequests instanceof Array) { return requestStates .some(state => activeRequests.includes(state)); } else if (activeRequests instanceof Object) { // works as else if return requestStates .some(state => Object.keys(activeRequests).includes(state)); } else { console.warn( 'Loader: did not receive a valid requestStates object: ', requestStates ); return false; } })(); // call actions, but throttle if repeating actionsList.forEach(action => { if (!deepIncludes(shallowDesymbolize(this.currentRequests), shallowDesymbolize(action))) { this.currentRequests.push(action); dispatch(action); } }); // needsDispatch should be "true" only for the first render pass this.needsDispatch = false; // return function that takes a component which will be rendered when // none of the request states is active const Throbber = (this.props.throbber || function(props) { return ( <div className={ props.throbberClass || "loader layout--flex" } > <h1>Loading...</h1> </div> ); }); // in other words: // IF requesting RENDER throbber // ELSE render given component if (requestsBusy) { return (<Throbber />); } else { return ( <WrappedComponent { ...this.props } /> ); } } } return connect(waitInjector)(Loader); }; }