react-magnetic-di
Version:
Context driven dependency injection
67 lines (58 loc) • 2.84 kB
JavaScript
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React, { useContext, useMemo, forwardRef } from 'react';
import PropTypes from 'prop-types';
import { KEY } from './constants';
import { Context } from './context';
import { getDisplayName } from './utils';
export var DiProvider = function DiProvider(_ref) {
var children = _ref.children,
use = _ref.use,
target = _ref.target;
var _useContext = useContext(Context),
_getDependencies = _useContext.getDependencies; // memo provider value so gets computed only once
var value = useMemo(function () {
// create a map of dependency real -> replacement for fast lookup
var replacementMap = use.reduce(function (m, d) {
return m.set(d[KEY], d);
}, new Map()); // support single or multiple targets
var targets = target && (Array.isArray(target) ? target : [target]);
return {
getDependencies: function getDependencies(realDeps, targetChild) {
// First we collect dependencies from parent provider(s) (if any)
var dependencies = _getDependencies(realDeps, targetChild); // If no target or target is in the array of targets, map use
if (!targetChild || !targets || targets.includes(targetChild)) {
return dependencies.map(function (dep) {
// 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
var real = dep[KEY] || dep;
return replacementMap.get(real) || dep;
});
}
return dependencies;
}
};
}, [_getDependencies]); // ignore use & target props
return /*#__PURE__*/React.createElement(Context.Provider, {
value: value
}, children);
};
DiProvider.propTypes = {
children: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
target: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.func)]),
use: PropTypes.arrayOf(PropTypes.func).isRequired
};
export function withDi(Comp, deps) {
var target = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
var WrappedComponent = /*#__PURE__*/forwardRef(function (props, ref) {
return /*#__PURE__*/React.createElement(DiProvider, {
use: deps,
target: target
}, /*#__PURE__*/React.createElement(Comp, _extends({
ref: ref
}, props)));
});
WrappedComponent.displayName = getDisplayName(Comp, 'withDi');
return WrappedComponent;
}