UNPKG

react-use-api

Version:

<div align="center"> <h1> <img width="120" src="./icon.svg"> <br/> React useApi() <br /> <br /> </h1> </div>

118 lines (113 loc) 3.96 kB
import { configure, axiosAll, defaultSettings, isFunction } from './common' export const feedRequests = async ( context: ReactUseApi.Context, ssrHtml: string, maxRequests = context.settings.maxRequests ) => { const { settings, collection: { ssrConfigs, cacheKeys }, } = context const { cache, renderSSR, debug } = settings if (!ssrConfigs.length) { if (debug) { console.log('[ReactUseApi][Requests Count] =', cacheKeys.size) console.log( '[ReactUseApi][Executed Times] =', settings.maxRequests - maxRequests ) } cacheKeys.clear() return ssrHtml // done } debug && console.log('[ReactUseApi][Collecting Requests]') if (maxRequests === 0) { console.error( '[ReactUseApi][ERROR] - Maximum executing times while fetching axios requests', '[congis]:', ssrConfigs, '[Executed Times]:', settings.maxRequests - maxRequests ) cacheKeys.clear() return ssrHtml // done } // The algorithm is collecting the unobtained API request config from the previous renderSSR() // , but here only fetches the API data from the first config and again uses renderSSR() to feed the data to its components. // This approach may look like inefficient but rather stable, since each config may rely on the data from useApi(). // However, it is possible that no one request config that depends on another one, only one renderSSR() is needed // , but who can guarantee that every developer is able to consider this dependency? // react-apollo uses the similar algorithm // https://github.com/apollographql/react-apollo/blob/master/packages/ssr/src/getDataFromTree.ts const { config, cacheKey } = ssrConfigs[0] // fetch the first const cacheData = cache.get(cacheKey) if (!cacheData) { try { debug && console.log('[ReactUseApi][Fetch]', cacheKey) const response = await axiosAll(context, config) cache.set(cacheKey, { response, }) } catch (error) { // is an axios error if (error?.response?.data) { cache.set(cacheKey, { // should not be error (Error) object in SSR, it will lead an error: Converting circular structure to JSON error: error.response, }) } else { throw error } } } // execute renderSSR one after another to get more ssrConfigs ssrConfigs.length = 0 ssrHtml = renderSSR() return await feedRequests(context, ssrHtml, --maxRequests) } export const injectSSRHtml = async ( context: ReactUseApi.CustomContext, renderSSR?: ReactUseApi.Settings['renderSSR'], postProcess?: (ssrHtml: string, apiCacheScript: string) => string ) => { context = configure(context, true) const { settings } = context settings.renderSSR = renderSSR || settings.renderSSR const { cache, useCacheData, clientCacheVar, shouldUseApiCache } = settings cache.reset() // collect API requests first let ssrHtml = settings.renderSSR() ssrHtml = await exports.feedRequests(context, ssrHtml) if (useCacheData) { const cacheJson = cache.dump().filter(({ k: cacheKey }) => { let config: ReactUseApi.Config try { config = JSON.parse(cacheKey) } catch (e) { config = {} } return shouldUseApiCache(config, cacheKey) !== false }) const apiCacheScript = Object.keys(cacheJson) ? `<script>window.${clientCacheVar} = ${JSON.stringify(cacheJson).replace( /</g, '\\u003c' )}</script>` : '' return isFunction(postProcess) ? postProcess(ssrHtml, apiCacheScript) : ssrHtml + apiCacheScript } return ssrHtml } export const loadApiCache = ( context: ReactUseApi.Context = { settings: defaultSettings } ) => { const { settings } = context const { clientCacheVar } = settings const data = window[clientCacheVar] if (Array.isArray(data)) { settings.cache.load(data) delete window[clientCacheVar] } }