All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.infinite.dist.index.esm.js Maven / Gradle / Ivy

There is a newer version: 2.2.5
Show newest version
import { useRef, useCallback } from 'react';
import useSWR from 'swr';
import { withMiddleware, createCacheHelper, isUndefined, useIsomorphicLayoutEffect, serialize, UNDEFINED, isFunction } from 'swr/_internal';
import { useSyncExternalStore } from 'use-sync-external-store/shim/index.js';

// We have to several type castings here because `useSWRInfinite` is a special
const INFINITE_PREFIX = '$inf$';
const EMPTY_PROMISE = Promise.resolve();
const getFirstPageKey = (getKey)=>{
    return serialize(getKey ? getKey(0, null) : null)[0];
};
const unstable_serialize = (getKey)=>{
    return INFINITE_PREFIX + getFirstPageKey(getKey);
};
const infinite = (useSWRNext)=>{
    return (getKey, fn, config)=>{
        const didMountRef = useRef(false);
        const dataRef = useRef();
        const { cache , initialSize =1 , revalidateAll =false , persistSize =false , revalidateFirstPage =true , revalidateOnMount =false , parallel =false  } = config;
        // The serialized key of the first page. This key will be used to store
        // metadata of this SWR infinite hook.
        let infiniteKey;
        try {
            infiniteKey = getFirstPageKey(getKey);
            if (infiniteKey) infiniteKey = INFINITE_PREFIX + infiniteKey;
        } catch (err) {
        // Not ready yet.
        }
        const [get, set, subscribeCache] = createCacheHelper(cache, infiniteKey);
        const getSnapshot = useCallback(()=>{
            const size = isUndefined(get()._l) ? initialSize : get()._l;
            return size;
        // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [
            cache,
            infiniteKey,
            initialSize
        ]);
        useSyncExternalStore(useCallback((callback)=>{
            if (infiniteKey) return subscribeCache(infiniteKey, ()=>{
                callback();
            });
            return ()=>{};
        }, // eslint-disable-next-line react-hooks/exhaustive-deps
        [
            cache,
            infiniteKey
        ]), getSnapshot, getSnapshot);
        const resolvePageSize = useCallback(()=>{
            const cachedPageSize = get()._l;
            return isUndefined(cachedPageSize) ? initialSize : cachedPageSize;
        // `cache` isn't allowed to change during the lifecycle
        // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [
            infiniteKey,
            initialSize
        ]);
        // keep the last page size to restore it with the persistSize option
        const lastPageSizeRef = useRef(resolvePageSize());
        // When the page key changes, we reset the page size if it's not persisted
        useIsomorphicLayoutEffect(()=>{
            if (!didMountRef.current) {
                didMountRef.current = true;
                return;
            }
            if (infiniteKey) {
                // If the key has been changed, we keep the current page size if persistSize is enabled
                // Otherwise, we reset the page size to cached pageSize
                set({
                    _l: persistSize ? lastPageSizeRef.current : resolvePageSize()
                });
            }
        // `initialSize` isn't allowed to change during the lifecycle
        // eslint-disable-next-line react-hooks/exhaustive-deps
        }, [
            infiniteKey,
            cache
        ]);
        // Needs to check didMountRef during mounting, not in the fetcher
        const shouldRevalidateOnMount = revalidateOnMount && !didMountRef.current;
        // Actual SWR hook to load all pages in one fetcher.
        const swr = useSWRNext(infiniteKey, async ()=>{
            // get the revalidate context
            const [forceRevalidateAll, originalData] = get()._i || [];
            // return an array of page data
            const data = [];
            const pageSize = resolvePageSize();
            const revalidators = [];
            let previousPageData = null;
            for(let i = 0; i < pageSize; ++i){
                const [pageKey, pageArg] = serialize(getKey(i, parallel ? null : previousPageData));
                if (!pageKey) {
                    break;
                }
                const [getSWRCache, setSWRCache] = createCacheHelper(cache, pageKey);
                // Get the cached page data.
                let pageData = getSWRCache().data;
                // should fetch (or revalidate) if:
                // - `revalidateAll` is enabled
                // - `mutate()` called
                // - the cache is missing
                // - it's the first page and it's not the initial render
                // - `revalidateOnMount` is enabled and it's on mount
                // - cache for that page has changed
                const shouldFetchPage = revalidateAll || forceRevalidateAll || isUndefined(pageData) || revalidateFirstPage && !i && !isUndefined(dataRef.current) || shouldRevalidateOnMount || originalData && !isUndefined(originalData[i]) && !config.compare(originalData[i], pageData);
                if (fn && shouldFetchPage) {
                    const revalidate = async ()=>{
                        pageData = await fn(pageArg);
                        setSWRCache({
                            data: pageData,
                            _k: pageArg
                        });
                        data[i] = pageData;
                    };
                    if (parallel) {
                        revalidators.push(revalidate);
                    } else {
                        await revalidate();
                    }
                } else {
                    data[i] = pageData;
                }
                if (!parallel) {
                    previousPageData = pageData;
                }
            }
            // flush all revalidateions in parallel
            if (parallel) {
                await Promise.all(revalidators.map((r)=>r()));
            }
            // once we executed the data fetching based on the context, clear the context
            set({
                _i: UNDEFINED
            });
            // return the data
            return data;
        }, config);
        // update dataRef
        useIsomorphicLayoutEffect(()=>{
            dataRef.current = swr.data;
        }, [
            swr.data
        ]);
        const mutate = useCallback(// eslint-disable-next-line func-names
        function(data, opts) {
            // When passing as a boolean, it's explicitly used to disable/enable
            // revalidation.
            const options = typeof opts === 'boolean' ? {
                revalidate: opts
            } : opts || {};
            // Default to true.
            const shouldRevalidate = options.revalidate !== false;
            // It is possible that the key is still falsy.
            if (!infiniteKey) return EMPTY_PROMISE;
            if (shouldRevalidate) {
                if (!isUndefined(data)) {
                    // We only revalidate the pages that are changed
                    const originalData = dataRef.current;
                    set({
                        _i: [
                            false,
                            originalData
                        ]
                    });
                } else {
                    // Calling `mutate()`, we revalidate all pages
                    set({
                        _i: [
                            true
                        ]
                    });
                }
            }
            return arguments.length ? swr.mutate(data, {
                ...options,
                revalidate: shouldRevalidate
            }) : swr.mutate();
        }, // swr.mutate is always the same reference
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [
            infiniteKey,
            cache
        ]);
        // Function to load pages data from the cache based on the page size.
        const resolvePagesFromCache = (pageSize)=>{
            // return an array of page data
            const data = [];
            let previousPageData = null;
            for(let i = 0; i < pageSize; ++i){
                var _cache_get;
                const [pageKey] = serialize(getKey(i, previousPageData));
                // Get the cached page data.
                const pageData = pageKey ? (_cache_get = cache.get(pageKey)) == null ? void 0 : _cache_get.data : UNDEFINED;
                // Return the current data if we can't get it from the cache.
                if (isUndefined(pageData)) return dataRef.current;
                data.push(pageData);
                previousPageData = pageData;
            }
            // Return the data
            return data;
        };
        // Extend the SWR API
        const setSize = useCallback((arg)=>{
            // It is possible that the key is still falsy.
            if (!infiniteKey) return EMPTY_PROMISE;
            let size;
            if (isFunction(arg)) {
                size = arg(resolvePageSize());
            } else if (typeof arg == 'number') {
                size = arg;
            }
            if (typeof size != 'number') return EMPTY_PROMISE;
            set({
                _l: size
            });
            lastPageSizeRef.current = size;
            return mutate(resolvePagesFromCache(size));
        }, // `cache` and `rerender` isn't allowed to change during the lifecycle
        // eslint-disable-next-line react-hooks/exhaustive-deps
        [
            infiniteKey,
            resolvePageSize,
            mutate,
            cache
        ]);
        // Use getter functions to avoid unnecessary re-renders caused by triggering
        // all the getters of the returned swr object.
        return {
            size: resolvePageSize(),
            setSize,
            mutate,
            get data () {
                return swr.data;
            },
            get error () {
                return swr.error;
            },
            get isValidating () {
                return swr.isValidating;
            },
            get isLoading () {
                return swr.isLoading;
            }
        };
    };
};
var index = withMiddleware(useSWR, infinite);

export { index as default, infinite, unstable_serialize };




© 2015 - 2024 Weber Informatics LLC | Privacy Policy