UNPKG

@nfq/react-ssr

Version:

An helper bundle for react with ssr setup

193 lines (163 loc) 5.54 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.storeFactory = exports.storeMap = exports.registerStore = exports.getStoreIdent = exports.DataConnector = void 0; var _reactEasyState = require("@risingstack/react-easy-state"); var _propTypes = _interopRequireDefault(require("prop-types")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const storeMap = {}; /** * Creates stores usable for front and backend and also the needed functions and api's to work together. * * @param {String} name The store name. (Best is to use the same name as the variable has the store is saved in). * @param {Object} storeData The data the store has in it. (Functions and properties.) * * @returns {Proxy} An store proxy. */ exports.storeMap = storeMap; const storeFactory = (name, storeData) => { const storeDataName = getStoreIdent(name); const data = Object.keys(storeData).reduce((acc, val) => { // eslint-disable-next-line security/detect-object-injection if (typeof storeData[val] === 'function') { // eslint-disable-next-line security/detect-object-injection acc.storeFunc[val] = storeData[val]; } else { // eslint-disable-next-line security/detect-object-injection acc.storeData[val] = storeData[val]; } return acc; }, { storeData: {}, storeFunc: {} }); const storeResult = (0, _reactEasyState.store)({ data: { ...data.storeData }, ...data.storeFunc, initData() { if (typeof window !== 'undefined') { // eslint-disable-next-line security/detect-object-injection if (window[storeDataName]) { // eslint-disable-next-line security/detect-object-injection this.data = window[storeDataName]; } } } }); storeResult.initData(); registerStore(storeDataName, storeResult); return storeResult; }; /** * Gets the store ident used for the name given. * * @param {String} name The store name used to create an store. * * @returns {String} The store data ident. */ exports.storeFactory = storeFactory; const getStoreIdent = name => `__${name.toUpperCase()}__`; /** * Registers an created store to the store map. * * @param {String} name The store map ident (usually the same as the data ident). * @param {Proxy} storeObj The store proxy object. */ exports.getStoreIdent = getStoreIdent; const registerStore = (name, storeObj) => { // eslint-disable-next-line security/detect-object-injection if (typeof storeMap[name] === 'undefined') { // eslint-disable-next-line security/detect-object-injection storeMap[name] = storeObj; } }; /** * An higher order component class that gives an Screen component all needed functionallity to load and retrieve data on server and client. * * @param {Object} Class The class to add the functionallity to. * @param {Array} UsedStores An array of objects that have the following properties: {name: String, functions: Array} * * @returns {Object} Returns an new class with all functions needed. */ exports.registerStore = registerStore; const DataConnector = (Class, UsedStores) => { var _class, _temp; const storeInfo = UsedStores.map(storeData => { // eslint-disable-next-line no-param-reassign storeData.name = getStoreIdent(storeData.name); return storeData; }); return _temp = _class = class ConnectedClass extends Class { /** * Fetches data from Store. * * @static * @param {Function} fetch The fetch function. (fetch in browser, node-fetch in node). * @param {Object} storeObj The storeObject. * @param {String} func The function name to use. * @param {String} [id=null] The data id for this store. * * @memberof ConnectedClass */ static async fetchData(fetch, storeObj, func, id = null) { // eslint-disable-next-line security/detect-object-injection return storeObj[func](fetch, id); } /** * Creates an instance of ConnectedClass. * * @param {Object} props Component props. * * @memberof ConnectedClass */ constructor(props) { super(props); const { staticContext } = props; if (staticContext) { const usableIdents = ConnectedClass.storeIdents.map(item => item.name); staticContext.stores.filter(item => usableIdents.includes(item.dataId)).forEach(storeData => { storeMap[storeData.dataId].data = storeData.storeData; }); } } /** * Fetches data. * * @memberof ConnectedClass */ componentDidMount() { const { contentId, match } = this.props; const stores = UsedStores.map(storeData => ({ ...storeData, store: storeMap[storeData.name] })); let id; if (match) { id = match.params.id; } else if (contentId) { id = contentId; } stores.forEach(storeData => { storeData.functions.forEach(func => { ConnectedClass.fetchData(fetch, storeData.store, func, id); }); }); if (typeof super.componentDidMount === 'function') { super.componentDidMount(); } } }, _class.propTypes = { match: _propTypes.default.object, staticContext: _propTypes.default.object }, _class.defaultProps = { match: null, staticContext: null }, _class.storeIdents = storeInfo, _temp; }; exports.DataConnector = DataConnector;