@solidjs/router
Advanced tools
Comparing version 0.14.10 to 0.15.0
@@ -13,2 +13,6 @@ import { JSX } from "solid-js"; | ||
export declare function useAction<T extends Array<any>, U, V>(action: Action<T, U, V>): (...args: Parameters<Action<T, U, V>>) => Promise<NarrowResponse<U>>; | ||
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U, T>; | ||
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, name?: string): Action<T, U>; | ||
export declare function action<T extends Array<any>, U = void>(fn: (...args: T) => Promise<U>, options?: { | ||
name?: string; | ||
onComplete?: (s: Submission<T, U>) => boolean; | ||
}): Action<T, U>; |
@@ -5,3 +5,3 @@ import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js"; | ||
import { mockBase } from "../utils.js"; | ||
import { cacheKeyOp, hashKey, revalidate, cache } from "./cache.js"; | ||
import { cacheKeyOp, hashKey, revalidate, query } from "./query.js"; | ||
export const actions = /* #__PURE__ */ new Map(); | ||
@@ -28,4 +28,4 @@ export function useSubmissions(fn, filter) { | ||
get(_, property) { | ||
if (submissions.length === 0 && property === "clear" || property === "retry") | ||
return (() => { }); | ||
if ((submissions.length === 0 && property === "clear") || property === "retry") | ||
return () => { }; | ||
return submissions[submissions.length - 1]?.[property]; | ||
@@ -39,3 +39,3 @@ } | ||
} | ||
export function action(fn, name) { | ||
export function action(fn, options = {}) { | ||
function mutate(...variables) { | ||
@@ -52,2 +52,14 @@ const router = this.r; | ||
const result = await handleResponse(res, error, router.navigatorFactory()); | ||
let retry = null; | ||
!o.onComplete?.({ | ||
...submission, | ||
result: result?.data, | ||
error: result?.error, | ||
pending: false, | ||
retry() { | ||
return retry = submission.retry(); | ||
} | ||
}); | ||
if (retry) | ||
return retry; | ||
if (!result) | ||
@@ -76,3 +88,3 @@ return submission.clear(); | ||
clear() { | ||
router.submissions[1](v => v.filter(i => i.input !== variables)); | ||
router.submissions[1](v => v.filter(i => i !== submission)); | ||
}, | ||
@@ -88,4 +100,5 @@ retry() { | ||
} | ||
const o = typeof options === "string" ? { name: options } : options; | ||
const url = fn.url || | ||
(name && `https://action/${name}`) || | ||
(o.name && `https://action/${o.name}`) || | ||
(!isServer ? `https://action/${hashString(fn.toString())}` : ""); | ||
@@ -151,3 +164,3 @@ mutate.base = url; | ||
// set cache | ||
flightKeys && flightKeys.forEach(k => cache.set(k, custom[k])); | ||
flightKeys && flightKeys.forEach(k => query.set(k, custom[k])); | ||
// trigger revalidation | ||
@@ -154,0 +167,0 @@ await revalidate(keys, false); |
export { createAsync, createAsyncStore, type AccessorWithLatest } from "./createAsync.js"; | ||
export { action, useSubmission, useSubmissions, useAction, type Action } from "./action.js"; | ||
export { cache, revalidate, type CachedFunction } from "./cache.js"; | ||
export { query, revalidate, cache, type CachedFunction } from "./query.js"; | ||
export { redirect, reload, json } from "./response.js"; |
export { createAsync, createAsyncStore } from "./createAsync.js"; | ||
export { action, useSubmission, useSubmissions, useAction } from "./action.js"; | ||
export { cache, revalidate } from "./cache.js"; | ||
export { query, revalidate, cache } from "./query.js"; | ||
export { redirect, reload, json } from "./response.js"; |
@@ -897,3 +897,3 @@ import { isServer, getRequestEvent, createComponent as createComponent$1, memo, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web'; | ||
for (let [k, v] of cacheMap.entries()) { | ||
if (!v[3].count && now - v[0] > CACHE_TIMEOUT) { | ||
if (!v[4].count && now - v[0] > CACHE_TIMEOUT) { | ||
cacheMap.delete(k); | ||
@@ -915,3 +915,3 @@ } | ||
force && (entry[0] = 0); //force cache miss | ||
entry[3][1](now); // retrigger live signals | ||
entry[4][1](now); // retrigger live signals | ||
}); | ||
@@ -926,3 +926,3 @@ }); | ||
} | ||
function cache(fn, name) { | ||
function query(fn, name) { | ||
// prioritize GET for server functions | ||
@@ -956,10 +956,10 @@ if (fn.GET) fn = fn.GET; | ||
tracking = true; | ||
onCleanup(() => cached[3].count--); | ||
onCleanup(() => cached[4].count--); | ||
} | ||
if (cached && cached[0] && (isServer || intent === "native" || cached[3].count || Date.now() - cached[0] < PRELOAD_TIMEOUT)) { | ||
if (cached && cached[0] && (isServer || intent === "native" || cached[4].count || Date.now() - cached[0] < PRELOAD_TIMEOUT)) { | ||
if (tracking) { | ||
cached[3].count++; | ||
cached[3][0](); // track | ||
cached[4].count++; | ||
cached[4][0](); // track | ||
} | ||
if (cached[2] === "preload" && intent !== "preload") { | ||
if (cached[3] === "preload" && intent !== "preload") { | ||
cached[0] = now; | ||
@@ -970,3 +970,3 @@ } | ||
res = "then" in cached[1] ? cached[1].then(handleResponse(false), handleResponse(true)) : handleResponse(false)(cached[1]); | ||
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version | ||
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version | ||
} | ||
@@ -981,11 +981,11 @@ inPreloadFn && "then" in res && res.catch(() => {}); | ||
cached[1] = res; | ||
cached[2] = intent; | ||
!isServer && intent === "navigate" && startTransition(() => cached[3][1](cached[0])); // update version | ||
cached[3] = intent; | ||
!isServer && intent === "navigate" && startTransition(() => cached[4][1](cached[0])); // update version | ||
} else { | ||
cache.set(key, cached = [now, res, intent, createSignal(now)]); | ||
cached[3].count = 0; | ||
cache.set(key, cached = [now, res,, intent, createSignal(now)]); | ||
cached[4].count = 0; | ||
} | ||
if (tracking) { | ||
cached[3].count++; | ||
cached[3][0](); // track | ||
cached[4].count++; | ||
cached[4][0](); // track | ||
} | ||
@@ -1030,2 +1030,3 @@ if (isServer) { | ||
if (error) throw v; | ||
cached[2] = v; | ||
return v; | ||
@@ -1039,3 +1040,7 @@ }; | ||
} | ||
cache.set = (key, value) => { | ||
query.get = key => { | ||
const cached = getCache().get(key); | ||
return cached[2]; | ||
}; | ||
query.set = (key, value) => { | ||
const cache = getCache(); | ||
@@ -1046,10 +1051,15 @@ const now = Date.now(); | ||
cached[0] = now; | ||
cached[1] = value; | ||
cached[2] = "preload"; | ||
cached[1] = Promise.resolve(value); | ||
cached[2] = value; | ||
cached[3] = "preload"; | ||
} else { | ||
cache.set(key, cached = [now, value,, createSignal(now)]); | ||
cached[3].count = 0; | ||
cache.set(key, cached = [now, Promise.resolve(value), value, "preload", createSignal(now)]); | ||
cached[4].count = 0; | ||
} | ||
}; | ||
cache.clear = () => getCache().clear(); | ||
query.delete = key => getCache().delete(key); | ||
query.clear = () => getCache().clear(); | ||
/** @deprecated use query instead */ | ||
const cache = query; | ||
function matchKey(key, keys) { | ||
@@ -1105,3 +1115,3 @@ for (let k of keys) { | ||
} | ||
function action(fn, name) { | ||
function action(fn, options = {}) { | ||
function mutate(...variables) { | ||
@@ -1120,2 +1130,13 @@ const router = this.r; | ||
const result = await handleResponse(res, error, router.navigatorFactory()); | ||
let retry = null; | ||
!o.onComplete?.({ | ||
...submission, | ||
result: result?.data, | ||
error: result?.error, | ||
pending: false, | ||
retry() { | ||
return retry = submission.retry(); | ||
} | ||
}); | ||
if (retry) return retry; | ||
if (!result) return submission.clear(); | ||
@@ -1140,3 +1161,3 @@ setResult(result); | ||
clear() { | ||
router.submissions[1](v => v.filter(i => i.input !== variables)); | ||
router.submissions[1](v => v.filter(i => i !== submission)); | ||
}, | ||
@@ -1151,3 +1172,6 @@ retry() { | ||
} | ||
const url = fn.url || name && `https://action/${name}` || (!isServer ? `https://action/${hashString(fn.toString())}` : ""); | ||
const o = typeof options === "string" ? { | ||
name: options | ||
} : options; | ||
const url = fn.url || o.name && `https://action/${o.name}` || (!isServer ? `https://action/${hashString(fn.toString())}` : ""); | ||
mutate.base = url; | ||
@@ -1207,3 +1231,3 @@ return toAction(mutate, url); | ||
// set cache | ||
flightKeys && flightKeys.forEach(k => cache.set(k, custom[k])); | ||
flightKeys && flightKeys.forEach(k => query.set(k, custom[k])); | ||
// trigger revalidation | ||
@@ -1675,2 +1699,2 @@ await revalidate(keys, false); | ||
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, usePreloadRoute, useResolvedPath, useSearchParams, useSubmission, useSubmissions }; | ||
export { A, HashRouter, MemoryRouter, Navigate, Route, Router, StaticRouter, mergeSearchString as _mergeSearchString, action, cache, createAsync, createAsyncStore, createBeforeLeave, createMemoryHistory, createRouter, json, keepDepth, notifyIfNotBlocked, query, redirect, reload, revalidate, saveCurrentDepth, useAction, useBeforeLeave, useCurrentMatches, useHref, useIsRouting, useLocation, useMatch, useNavigate, useParams, usePreloadRoute, useResolvedPath, useSearchParams, useSubmission, useSubmissions }; |
@@ -186,3 +186,3 @@ import type { Component, JSX, Signal } from "solid-js"; | ||
} | ||
export type CacheEntry = [number, any, Intent | undefined, Signal<number> & { | ||
export type CacheEntry = [number, Promise<any>, any, Intent | undefined, Signal<number> & { | ||
count: number; | ||
@@ -189,0 +189,0 @@ }]; |
@@ -9,3 +9,3 @@ { | ||
"license": "MIT", | ||
"version": "0.14.10", | ||
"version": "0.15.0", | ||
"homepage": "https://github.com/solidjs/solid-router#readme", | ||
@@ -12,0 +12,0 @@ "repository": { |
@@ -430,19 +430,19 @@ <p> | ||
### `cache` | ||
### `query` | ||
To prevent duplicate fetching and to trigger handle refetching we provide a cache api. That takes a function and returns the same function. | ||
To prevent duplicate fetching and to trigger handle refetching we provide a query api. That takes a function and returns the same function. | ||
```jsx | ||
const getUser = cache(async (id) => { | ||
const getUser = query(async (id) => { | ||
return (await fetch(`/api/users${id}`)).json() | ||
}, "users") // used as cache key + serialized arguments | ||
}, "users") // used as the query key + serialized arguments | ||
``` | ||
It is expected that the arguments to the cache function are serializable. | ||
It is expected that the arguments to the query function are serializable. | ||
This cache accomplishes the following: | ||
This query accomplishes the following: | ||
1. It does just deduping on the server for the lifetime of the request. | ||
2. It does preload cache in the browser which lasts 5 seconds. When a route is preloaded on hover or when preload is called when entering a route it will make sure to dedupe calls. | ||
1. It does deduping on the server for the lifetime of the request. | ||
2. It fills a preload cache in the browser which lasts 5 seconds. When a route is preloaded on hover or when preload is called when entering a route it will make sure to dedupe calls. | ||
3. We have a reactive refetch mechanism based on key. So we can tell routes that aren't new to retrigger on action revalidation. | ||
4. It will serve as a back/forward cache for browser navigation up to 5 mins. Any user based navigation or link click bypasses it. Revalidation or new fetch updates the cache. | ||
4. It will serve as a back/forward cache for browser navigation up to 5 mins. Any user based navigation or link click bypasses this cache. Revalidation or new fetch updates the cache. | ||
@@ -454,3 +454,3 @@ Using it with preload function might look like: | ||
import { Route } from "@solidjs/router"; | ||
import { getUser } from ... // the cache function | ||
import { getUser } from ... // the query function | ||
@@ -472,3 +472,3 @@ const User = lazy(() => import("./pages/users/[id].js")); | ||
// pages/users/[id].js | ||
import { getUser } from ... // the cache function | ||
import { getUser } from ... // the query function | ||
@@ -489,5 +489,5 @@ export default function User(props) { | ||
You can revalidate the cache using the `revalidate` method or you can set `revalidate` keys on your response from your actions. If you pass the whole key it will invalidate all the entries for the cache (ie "users" in the example above). You can also invalidate a single entry by using `keyFor`. | ||
You can revalidate the query using the `revalidate` method or you can set `revalidate` keys on your response from your actions. If you pass the whole key it will invalidate all the entries for the query (ie "users" in the example above). You can also invalidate a single entry by using `keyFor`. | ||
`cache` can be defined anywhere and then used inside your components with: | ||
`query` can be defined anywhere and then used inside your components with: | ||
@@ -509,3 +509,3 @@ ### `createAsync` | ||
Using `cache` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly. | ||
Using `query` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly. | ||
@@ -566,3 +566,5 @@ ### `createAsyncStore` | ||
#### Notes of `<form>` implementation and SSR | ||
Actions also a second argument which can be the name or an option object with `name` and `onComplete`. `name` is used to identify SSR actions that aren't server functions (see note below). `onComplete` allows you to configure behavior when `action`s complete. Keep in mind `onComplete` does not work when JavaScript is disabled. | ||
#### Notes on `<form>` implementation and SSR | ||
This requires stable references as you can only serialize a string as an attribute, and across SSR they'd need to match. The solution is providing a unique name. | ||
@@ -606,3 +608,3 @@ | ||
These are used to communicate router navigations from cache/actions, and can include invalidation hints. Generally these are thrown to not interfere the with the types and make it clear that function ends execution at that point. | ||
These are used to communicate router navigations from query/actions, and can include invalidation hints. Generally these are thrown to not interfere the with the types and make it clear that function ends execution at that point. | ||
@@ -613,3 +615,3 @@ #### `redirect(path, options)` | ||
```js | ||
const getUser = cache(() => { | ||
const getUser = query(() => { | ||
const user = await api.getCurrentUser() | ||
@@ -625,3 +627,3 @@ if (!user) throw redirect("/login"); | ||
```js | ||
const getTodo = cache(async (id: number) => { | ||
const getTodo = query(async (id: number) => { | ||
const todo = await fetchTodo(id); | ||
@@ -949,3 +951,3 @@ return todo; | ||
These have been replaced by a preload mechanism. This allows link hover preloads (as the preload function can be run as much as wanted without worry about reactivity). It support deduping/cache APIs which give more control over how things are cached. It also addresses TS issues with getting the right types in the Component without `typeof` checks. | ||
These have been replaced by a preload mechanism. This allows link hover preloads (as the preload function can be run as much as wanted without worry about reactivity). It support deduping/query APIs which give more control over how things are cached. It also addresses TS issues with getting the right types in the Component without `typeof` checks. | ||
@@ -952,0 +954,0 @@ That being said you can reproduce the old pattern largely by turning off preloads at the router level and then injecting your own Context: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
183628
47
4110
1001