UNPKG

react-magnetic-di

Version:
86 lines (85 loc) 3.29 kB
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } import React, { forwardRef, Component } from 'react'; import PropTypes from 'prop-types'; import { diRegistry } from './constants'; import { Context } from './context'; import { addInjectableToMap, getDisplayName, findInjectable } from './utils'; import { globalDi } from './global'; export class DiProvider extends Component { constructor(...args) { super(...args); this.value = undefined; } componentDidCatch(err) { globalDi._remove(this.props.use); throw err; } componentWillUnmount() { globalDi._remove(this.props.use); } getValue() { if (this.value) return this.value; const { use, target, global } = this.props; const { getDependencies } = this.context; // create a map of dependency real -> replacements for fast lookup const replacementMap = use.reduce((acc, inj) => { addInjectableToMap(acc, inj); return acc; }, new Map()); // supports global di if needed globalDi._fromProvider(use, { global }); // support single or multiple targets const targets = target && new WeakSet(Array.isArray(target) ? target : [target]); this.value = { getDependencies(realDeps, targetChild) { // First we collect dependencies from parent provider(s) (if any) const dependencies = getDependencies(realDeps, targetChild); // If no target or target is in the array of targets, map use if (!targets || targets.has(targetChild)) { for (let i = 0; i < dependencies.length; i++) { // dep can be either the original or a replacement // if another provider at the top has already swapped it // so we check if here we need to inject a different one // or return the original / parent replacement const dep = dependencies[i]; const real = diRegistry.has(dep) ? diRegistry.get(dep).from : dep; const replacedInj = findInjectable(replacementMap, real, targetChild); if (replacedInj) dependencies[i] = replacedInj.value; } } return dependencies; } }; return this.value; } render() { return /*#__PURE__*/React.createElement(Context.Provider, { value: this.getValue() }, this.props.children); } } DiProvider.contextType = Context; DiProvider.propTypes = { children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]), global: PropTypes.bool, target: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.func)]), use: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object])).isRequired }; export function withDi(Comp, deps, target = null) { const WrappedComponent = /*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/React.createElement(DiProvider, { use: deps, target: target }, /*#__PURE__*/React.createElement(Comp, _extends({ ref: ref }, props)))); WrappedComponent.displayName = getDisplayName(Comp, 'withDi'); return WrappedComponent; }