UNPKG

@shopify/react-async

Version:

Tools for creating powerful, asynchronously-loaded React components

86 lines (83 loc) 2.31 kB
import { useState, useCallback, useContext } from 'react'; import { useServerEffect } from '@shopify/react-effect'; import { useMountedRef } from '@shopify/react-hooks'; import { AsyncAssetContext } from './context/assets.mjs'; function usePreload(...args) { const [preloadable, options = {}] = args; return preloadable.usePreload(options); } function usePrefetch(...args) { const [prefetchable, options = {}] = args; return prefetchable.usePrefetch(options); } function useKeepFresh(...args) { const [keepFreshable, options = {}] = args; return keepFreshable.useKeepFresh(options); } function useAsync(resolver, { assets, scripts = assets, styles = assets, immediate = true } = {}) { const [value, setValue] = useState(() => immediate || typeof window !== 'undefined' ? resolver.resolved : null); const mounted = useMountedRef(); const load = useCallback(async () => { if (value != null) { return value; } try { const resolved = await resolver.resolve(); if (mounted.current) { // It's important to use the function form of setValue here. // Resolved is going to be a function in most cases, since it's // a React component. If you do not set it using the function form, // React treats the component as the function that returns state, // so it sets state with the result of manually calling the component // (so, usually JSX). setValue(() => resolved); } return resolved; } catch (error) { if (mounted.current) { setValue(error); } return error; } }, [mounted, resolver, value]); const { id } = resolver; useAsyncAsset(id, { scripts, styles }); return value instanceof Error ? { id, resolved: null, error: value, loading: false, load } : { id, resolved: value, error: null, loading: value == null, load }; } function useAsyncAsset(id, { scripts, styles } = {}) { const async = useContext(AsyncAssetContext); useServerEffect(() => { if (async && id) { async.markAsUsed(id, { scripts, styles }); } }, async === null || async === void 0 ? void 0 : async.effect); } export { useAsync, useAsyncAsset, useKeepFresh, usePrefetch, usePreload };