Source

flux-react/src/use-cache-reader/use-cache-reader.js

//#region Imports

import { useState } from 'react';
import { useOnEmit } from '@psionic/emit-react';

//#endregion

//#region Typedefs

/**
 * The data currently in the cache, whether it is stale or not. If another piece of data is currently being loaded, the old
 * cached data will be represented here still.
 * @typedef {*} CachedValue
 *
 * @memberof module:@psionic/flux-react
 * @alias module:@psionic/flux-react.CachedData
 */

/**
 * Boolean state value tracking whether the data in the cache is currently stale or not.
 * @typedef {boolean} IsStaleFlag
 *
 * @memberof module:@psionic/flux-react
 * @alias module:@psionic/flux-react.IsStaleFlag
 */

/**
 * Boolean state value tracking whether the data in the cache is currently being loaded or not.
 * @typedef {boolean} IsLoadingFlag
 *
 * @memberof module:@psionic/flux-react
 * @alias module:@psionic/flux-react.IsLoadingFlag
 */

//#endregion

//#region Public Hooks

/**
 * React Hook that creates state values to interact with `@psionic/flux` `FluxCache` objects for the lifetime of the
 * React component the hook is used in.
 * @public
 * @memberof module:@psionic/flux-react
 *
 * @example
 * // Create a FluxCache object
 * const profileCache = createFluxCache({
 *      id: 'profileCache',
 *      fetch: async () => {
 *          // Mock a network request delay
 *          await delay(500);
 *          return { name: 'John' };
 *      },
 * });
 *
 * // In a React component, use the `useCacheReader` hook to respond to changes to this FluxCache
 * const [
 *      profile,
 *      profileIsStale,
 *      profileIsLoading,
 * ] = useCacheReader(profileCache);
 *
 * // The `profile` from the `useCacheReader` will contain `undefined` since that is the current value in the profile state
 * console.log(profile); // undefined
 *
 * // The `profileIsStale` value will be set to `true` since no data has been fetched yet
 * console.log(profileIsStale); // true
 *
 * // The `profileIsLoading` value will be set to `false` since the data is not loading currently
 * console.log(profileIsLoading); // false
 *
 * // Trigger a fetch operation from anywhere in your codebase
 * profileCache.get();
 *
 * // The `profile` will still contain the old data (in this case, undefined)
 * console.log(profile); // undefined
 *
 * // The `profileIsStale` value will still be set to `true` since the data has not been fetched yet
 * console.log(profileIsStale); // true
 *
 * // The `profileIsLoading` flag should now be set to `true` while the data is being fetched
 * console.log(profileIsLoading); // true
 *
 * // Wait for 500ms for the data to finish loading
 * await delay(delayTime);
 *
 * // The `profile` will now contain the new data
 * console.log(profile); // { name: 'John' }
 *
 * // The `profileIsStale` value will be set to `false` since the data was just fetched
 * console.log(profileIsStale); // false
 *
 * // The `profileIsLoading` value will be set to `false` since the data has finished loading
 * console.log(profileIsLoading); // false
 *
 * @param {module:@psionic/flux.FluxCache} fluxCache The `FluxCache` object to read data from as it changes
 * @returns {Array<CachedValue, IsStaleFlag, IsLoadingFlag>} Hook API for reading the FluxCache's data as React state
 */
function useCacheReader(fluxCache) {
    // Track some flux cache info in state
    const [cachedValue, setCachedValue] = useState(fluxCache.getCachedData());
    const [isStale, setIsStale] = useState(fluxCache.getStale());
    const [isLoading, setIsLoading] = useState(fluxCache.getIsLoading());

    // Use the `useOnEmit` hook to listen to updates for
    useOnEmit(`_FLUX_${fluxCache.getID()}-updated`, () => {
        setCachedValue(fluxCache.getCachedData());
        setIsStale(fluxCache.getStale());
        setIsLoading(fluxCache.getIsLoading());
    });

    return [
        cachedValue,
        isStale,
        isLoading,
    ];
}

//#endregion

//#region Exports

module.exports = {
    useCacheReader,
};

//#endregion