import { createSignal, createEffect, onCleanup, batch } from 'solid-js' import { createSWR } from '../../core' import type { SWRSignals, SWRResponse, Key, Fetcher, MutatorOptions } from './types' // Global SWR instance const globalSWR = createSWR() /** * Create SWR signals for Solid */ export function createSWRSignals( key: Key | null, fetcher?: Fetcher, config?: Partial> ): SWRSignals { // Update config if provided if (config) { globalSWR.updateConfig(config) } // Initial state logic let initialData: Data | undefined = undefined let initialError: Error | undefined = undefined let initialIsLoading = false let initialIsValidating = false if (key) { const entry = globalSWR.get(key) if (entry) { initialData = entry.data as Data initialError = entry.error as Error initialIsLoading = entry.isLoading initialIsValidating = entry.isValidating } else { initialData = config?.fallbackData } } // Create signals const [data, setData] = createSignal(initialData) const [error, setError] = createSignal(initialError) const [isLoading, setIsLoading] = createSignal(initialIsLoading) const [isValidating, setIsValidating] = createSignal(initialIsValidating) // Subscribe to SWR changes let unsubscribe: (() => void) | undefined if (key) { unsubscribe = globalSWR.subscribe(key, (newData, newError, newIsValidating, newIsLoading) => { batch(() => { setData(newData) setError(newError) setIsValidating(newIsValidating ?? false) setIsLoading(newIsLoading ?? false) }) }) } // Cleanup on destroy onCleanup(() => { unsubscribe?.() }) // Create mutate function const mutate = (mutateData?: Data | ((current: Data | undefined) => Data | Promise), options?: Partial>) => { if (!key) return Promise.resolve(undefined) return globalSWR.mutate(key, mutateData, options) } return { data, error, isLoading, isValidating, loading: isLoading, validating: isValidating, mutate } } /** * Create SWR response object for Solid */ export function createSWRResponse( key: Key | null, fetcher?: Fetcher, config?: Partial> ): SWRResponse { const signals = createSWRSignals(key, fetcher, config) return { get data() { return signals.data() }, get error() { return signals.error() }, get isLoading() { return signals.isLoading() }, get isValidating() { return signals.isValidating() }, get loading() { return signals.isLoading() }, get validating() { return signals.isValidating() }, mutate: signals.mutate } } /** * Hook-like function returning array [data, { mutate, error, isLoading, isValidating }] */ export function useSWR( key: Key | null, fetcher?: Fetcher, config?: Partial> ): [Data | undefined, SWRResponse] { const signals = createSWRSignals(key, fetcher, config) const response: SWRResponse = { get data() { return signals.data() }, get error() { return signals.error() }, get isLoading() { return signals.isLoading() }, get isValidating() { return signals.isValidating() }, get loading() { return signals.isLoading() }, get validating() { return signals.isValidating() }, mutate: signals.mutate } return [signals.data(), response] } /** * Individual signal creators */ export function swrDataSignal( key: Key | null, fetcher?: Fetcher, config?: Partial> ) { return createSWRSignals(key, fetcher, config as any).data } export function swrErrorSignal( key: Key | null, fetcher?: Fetcher, config?: Partial> ) { return createSWRSignals(key, fetcher, config).error } export function swrLoadingSignal( key: Key | null, fetcher?: Fetcher, config?: Partial> ) { return createSWRSignals(key, fetcher, config).isLoading } export function swrValidatingSignal( key: Key | null, fetcher?: Fetcher, config?: Partial> ) { return createSWRSignals(key, fetcher, config).isValidating } /** * Hook for manual mutation */ export function useSWRMutate() { return (key: Key, data?: Data | ((current: Data | undefined) => Data | Promise), options?: Partial>) => { return globalSWR.mutate(key, data, options) } } /** * Hook for accessing global SWR instance */ export function useSWRInstance() { return globalSWR } export default createSWRSignals