UNPKG

react-cms-firestore

Version:

Dependency-inject CMS data into any react component from the Firestore

80 lines (70 loc) 2.34 kB
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import cmsReadQueue from "./internal/CmsReadQueue"; import { CmsHelper } from "./internal/CmsHelper"; import React from 'react'; import Placeholder from "./internal/placeholder/Placeholder"; // Global singleton which acts as the cms which gets injected into components. if (!globalThis.cms_firestore) { globalThis.cms_firestore = {}; } /** * Injects CMS data into the component. * Pass in the cms keys for the data the component needs. * Waits until cms data is ready before rendering component. * * Access data with props.cms from inside component. */ export default function withCms(WrappedComponent, keys = [], placeHolderStyle) { return props => { if (!Array.isArray(keys)) { keys = [keys]; } const rootCms = globalThis.cms_firestore; const initialReadyState = keys.length === 0 || keys.every(key => key in rootCms); const [isCmsReady, setIsCmsReady] = useState(initialReadyState); const mountedRef = useRef(true); useEffect(() => { mountedRef.current = true; return () => { mountedRef.current = false; }; }, []); const readCms = useCallback(async keys => { cmsReadQueue.add(keys, rootCms); const waitPromises = []; for (const key of keys) { waitPromises.push(cmsReadQueue.waitForData(key, rootCms)); } const dataPerKey = await Promise.all(waitPromises); for (let i = 0; i < keys.length; i++) { const key = keys[i]; const data = dataPerKey[i]; CmsHelper.decode(data); rootCms[key] = data; } if (mountedRef.current) { setIsCmsReady(true); } }, []); useEffect(() => { if (isCmsReady) { return; } readCms(keys); }, [isCmsReady, readCms]); const content = useMemo(() => { if (!isCmsReady || placeHolderStyle && placeHolderStyle.test) { if (placeHolderStyle) { return /*#__PURE__*/React.createElement(Placeholder, { style: placeHolderStyle }); } else { return null; } } return /*#__PURE__*/React.createElement(WrappedComponent, Object.assign({}, props, { cms: rootCms })); }, [props, isCmsReady]); return content; }; }