feature-u
Version:
Feature Based Project Organization for React
105 lines (95 loc) • 3.87 kB
JavaScript
import React, {useContext} from 'react';
import {FassetsContext,
fassetsProps} from './withFassets';
import verify from '../util/verify';
import isPlainObject from 'lodash.isplainobject';
import isString from 'lodash.isstring';
import {MyObj} from '../util/mySpace';
/**
* A {{book.ext.reactHook}} that provides functional component access
* to **feature-u** {{book.api.fassets}}.
*
* **Hooks** allow you to **"hook into"** React state and lifecycle
* aspects _from functional components_. They greatly simplify the UI
* implementation _as opposed to the alternative of Higher Order
* Components (see: {{book.api.withFassets}})_.
*
* There are three ways to invoke `useFassets()` _(examples can be
* found at {{book.guide.crossCom_uiComposition}})_:
*
* 1. Passing NO parameters, returns the
* {{book.api.FassetsObject}}:
*
* ```js
* + useFassets(): fassets
* ```
*
* 2. Passing a `fassetsKey` _(a string)_, returns the resolved
* fassets resource:
*
* ```js
* + useFassets('MainPage.*.link@withKeys'): [] ... an array of cataloged links
* ```
*
* The `fassetsKey` parameter is identical _(in usage)_ to the
* {{book.api.Fassets_get}} method.
*
* 3. Passing a {{book.api.mapFassetsToPropsStruct}}, returns a set of
* resolved fassetsProps:
*
* ```js
* + useFassets({
* mainBodies: 'MainPage.*.body',
* mainLinks: 'MainPage.*.link@withKeys'
* }): { // ... return structure:
* mainBodies: ... resolved cataloged resource
* mainLinks: ... ditto
* }
* ```
*
* The {{book.api.mapFassetsToPropsStruct}} allows you to return
* more than one resolved fassets resources.
*
* **SideBar**: For `useFassets()` to operate,
* `<FassetsContext.Provider>` must be rendered at the root of your
* application DOM. This is really a moot point, because
* **feature-u** automatically performs this initialization, so you
* really don't have to worry about this detail _(automating
* configuration is a Hallmark of **feature-u** - reducing boilerplate
* code)_.
*
* @param {string|mapFassetsToPropsStruct} p the parameter controlling
* what `useFassets` does _(see explanation above)_.
*
* @returns {Fassets|fassets-resource|fassetsProps} _see explanation above_.
*
* @function useFassets
*/
export function useFassets(p='.') {
useFassetsCheck(p);
const fassets = useContext(FassetsContext);
return isString(p) ? fassets.get(p) : fassetsProps(p, fassets);
}
// check useFassets() usage in a way that is masked as a hook
// (useXyz()), so as to allow execution before real hooks
// ... i.e. fake out the lint rule!!
// ... this includes BOTH verifying:
// - hooks is available in this version of react
// - parameter validation
function useFassetsCheck(p) {
// verify that hooks are available in this version of react
if (!useContext) {
throw new Error(`feature-u useFassets() is only available in React versions that have HOOKS (React >=16.8) ... your React Version is: ${React.version}`);
}
// parameter validation
const check = verify.prefix('useFassets() parameter violation: ');
check(p, 'single parameter IS required');
check(isString(p) || isPlainObject(p), `single parameter must either be a string or a structure ... ${p}`);
// when a mapFassetsToProps is supplied, it must be a set of key/value pairs cataloging strings
if (isPlainObject(p)) {
MyObj.entries(p).forEach( ([propKey, fassetsKey]) => {
check(isString(fassetsKey),
`invalid mapFassetsToProps - all properties MUST reference a fassetsKey string ... at minimum ${propKey} does NOT`);
});
}
}