Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@solidjs/router

Package Overview
Dependencies
Maintainers
2
Versions
67
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@solidjs/router - npm Package Compare versions

Comparing version 0.10.0-beta.8 to 0.10.0-beta.9

1

dist/components.d.ts

@@ -10,2 +10,3 @@ import type { JSX } from "solid-js";

preload?: boolean;
link?: boolean;
}

@@ -12,0 +13,0 @@ }

2

dist/components.jsx

@@ -30,3 +30,3 @@ import { createMemo, mergeProps, splitProps } from "solid-js";

...rest.classList
}} aria-current={isActive() ? "page" : undefined}/>);
}} link aria-current={isActive() ? "page" : undefined}/>);
}

@@ -33,0 +33,0 @@ export function Navigate(props) {

import { JSX } from "solid-js";
import { Submission } from "../types";
export type Action<T extends Array<any>, U> = ((...vars: T) => Promise<U>) & JSX.SerializableAttributeValue & {
export type Action<T extends Array<any>, U> = (T extends [FormData] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<U>) & {
url: string;

@@ -5,0 +5,0 @@ with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => U, ...args: A): Action<B, U>;

@@ -8,2 +8,5 @@ import { type ReconcileOptions } from "solid-js/store";

export declare function cache<T extends (...args: any) => U | Response, U>(fn: T, name: string, options?: ReconcileOptions): CachedFunction<T, U>;
export declare namespace cache {
var set: (key: string, value: any) => void;
}
export declare function hashKey<T extends Array<any>>(args: T): string;

@@ -25,2 +25,4 @@ import { createSignal, getOwner, onCleanup, sharedConfig, startTransition } from "solid-js";

const req = getRequestEvent() || sharedConfig.context;
if (!req)
throw new Error("Cannot find cache context");
return req.routerCache || (req.routerCache = new Map());

@@ -82,4 +84,5 @@ }

// serialize on server
if (isServer && sharedConfig.context && !sharedConfig.context.noHydrate) {
sharedConfig.context && sharedConfig.context.serialize(key, res);
if (isServer && (sharedConfig.context && !sharedConfig.context.noHydrate)) {
const e = getRequestEvent();
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
}

@@ -135,2 +138,23 @@ if (cached) {

}
;
cache.set = (key, value) => {
const cache = getCache();
const now = Date.now();
let cached = cache.get(key);
let version;
if (getOwner()) {
version = createSignal(now, {
equals: (p, v) => v - p < 50 // margin of error
});
onCleanup(() => cached[3].delete(version));
}
if (cached) {
cached[0] = now;
cached[1] = value;
cached[2] = "preload";
version && cached[3].add(version);
}
else
cache.set(key, (cached = [now, value, , new Set(version ? [version] : [])]));
};
function matchKey(key, keys) {

@@ -137,0 +161,0 @@ for (let k of keys) {

import type { RouterContext } from "../types";
export declare function setupNativeEvents(router: RouterContext): void;
export declare function setupNativeEvents(preload?: boolean, explicitLinks?: boolean, actionBase?: string): (router: RouterContext) => void;
import { delegateEvents } from "solid-js/web";
import { onCleanup } from "solid-js";
import { actions } from "./action";
export function setupNativeEvents(router) {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout = {};
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
function handleAnchor(evt) {
if (evt.defaultPrevented ||
evt.button !== 0 ||
evt.metaKey ||
evt.altKey ||
evt.ctrlKey ||
evt.shiftKey)
return;
const a = evt
.composedPath()
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a)
return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || (!href && !a.hasAttribute("state")))
return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || (rel && rel.includes("external")))
return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin ||
(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
return;
return [a, url];
}
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state && JSON.parse(state)
});
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
if (!preloadTimeout[url.pathname])
router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorIn(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
if (preloadTimeout[url.pathname])
return;
preloadTimeout[url.pathname] = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
delete preloadTimeout[url.pathname];
}, 200);
}
function handleAnchorOut(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [, url] = res;
if (preloadTimeout[url.pathname]) {
clearTimeout(preloadTimeout[url.pathname]);
delete preloadTimeout[url.pathname];
export function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") {
return (router) => {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout = {};
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
}
function handleFormSubmit(evt) {
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
? evt.submitter.formAction
: evt.target.action;
if (!actionRef)
return;
if (!actionRef.startsWith("action:")) {
const url = new URL(actionRef);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(router.actionBase))
function handleAnchor(evt) {
if (evt.defaultPrevented ||
evt.button !== 0 ||
evt.metaKey ||
evt.altKey ||
evt.ctrlKey ||
evt.shiftKey)
return;
const a = evt
.composedPath()
.find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a || (explicitLinks && !a.getAttribute("link")))
return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || (!href && !a.hasAttribute("state")))
return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || (rel && rel.includes("external")))
return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin ||
(basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())))
return;
return [a, url];
}
const handler = actions.get(actionRef);
if (handler) {
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
const data = new FormData(evt.target);
handler.call(router, data);
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state && JSON.parse(state)
});
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
document.addEventListener("mouseover", handleAnchorIn);
document.addEventListener("mouseout", handleAnchorOut);
document.addEventListener("focusin", handleAnchorPreload);
document.addEventListener("touchstart", handleAnchorPreload);
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
document.removeEventListener("mouseover", handleAnchorIn);
document.removeEventListener("mouseout", handleAnchorOut);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
document.removeEventListener("submit", handleFormSubmit);
});
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
if (!preloadTimeout[url.pathname])
router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorIn(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [a, url] = res;
if (preloadTimeout[url.pathname])
return;
preloadTimeout[url.pathname] = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
delete preloadTimeout[url.pathname];
}, 200);
}
function handleAnchorOut(evt) {
const res = handleAnchor(evt);
if (!res)
return;
const [, url] = res;
if (preloadTimeout[url.pathname]) {
clearTimeout(preloadTimeout[url.pathname]);
delete preloadTimeout[url.pathname];
}
}
function handleFormSubmit(evt) {
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction")
? evt.submitter.formAction
: evt.target.action;
if (!actionRef)
return;
if (!actionRef.startsWith("action:")) {
const url = new URL(actionRef);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(actionBase))
return;
}
if (evt.target.method.toUpperCase() !== "POST")
throw new Error("Only POST forms are supported for Actions");
const handler = actions.get(actionRef);
if (handler) {
evt.preventDefault();
const data = new FormData(evt.target);
handler.call(router, data);
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
document.addEventListener("mouseover", handleAnchorIn);
document.addEventListener("mouseout", handleAnchorOut);
document.addEventListener("focusin", handleAnchorPreload);
document.addEventListener("touchstart", handleAnchorPreload);
}
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
if (preload) {
document.removeEventListener("mouseover", handleAnchorIn);
document.removeEventListener("mouseout", handleAnchorOut);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
}
document.removeEventListener("submit", handleFormSubmit);
});
};
}

@@ -424,3 +424,2 @@ import { isServer, getRequestEvent, createComponent as createComponent$1, delegateEvents, spread, mergeProps as mergeProps$1, template } from 'solid-js/web';

base: baseRoute,
actionBase: options.actionBase || "/_server",
location,

@@ -591,4 +590,3 @@ isRouting,

const {
base,
actionBase
base
} = props;

@@ -601,4 +599,3 @@ const routeDefs = children(() => props.children);

const routerState = createRouterContext(router, branches, {
base,
actionBase
base
});

@@ -774,2 +771,3 @@ router.create && router.create(routerState);

const req = getRequestEvent() || sharedConfig.context;
if (!req) throw new Error("Cannot find cache context");
return req.routerCache || (req.routerCache = new Map());

@@ -832,3 +830,4 @@ }

if (isServer && sharedConfig.context && !sharedConfig.context.noHydrate) {
sharedConfig.context && sharedConfig.context.serialize(key, res);
const e = getRequestEvent();
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
}

@@ -876,2 +875,21 @@ if (cached) {

}
cache.set = (key, value) => {
const cache = getCache();
const now = Date.now();
let cached = cache.get(key);
let version;
if (getOwner()) {
version = createSignal(now, {
equals: (p, v) => v - p < 50 // margin of error
});
onCleanup(() => cached[3].delete(version));
}
if (cached) {
cached[0] = now;
cached[1] = value;
cached[2] = "preload";
version && cached[3].add(version);
} else cache.set(key, cached = [now, value,, new Set(version ? [version] : [])]);
};
function matchKey(key, keys) {

@@ -1000,94 +1018,101 @@ for (let k of keys) {

function setupNativeEvents(router) {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout = {};
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
function handleAnchor(evt) {
if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a) return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || !href && !a.hasAttribute("state")) return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || rel && rel.includes("external")) return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
return [a, url];
}
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state && JSON.parse(state)
});
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
if (!preloadTimeout[url.pathname]) router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorIn(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
if (preloadTimeout[url.pathname]) return;
preloadTimeout[url.pathname] = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
delete preloadTimeout[url.pathname];
}, 200);
}
function handleAnchorOut(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [, url] = res;
if (preloadTimeout[url.pathname]) {
clearTimeout(preloadTimeout[url.pathname]);
delete preloadTimeout[url.pathname];
function setupNativeEvents(preload = true, explicitLinks = false, actionBase = "/_server") {
return router => {
const basePath = router.base.path();
const navigateFromRoute = router.navigatorFactory(router.base);
let preloadTimeout = {};
function isSvg(el) {
return el.namespaceURI === "http://www.w3.org/2000/svg";
}
}
function handleFormSubmit(evt) {
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.formAction : evt.target.action;
if (!actionRef) return;
if (!actionRef.startsWith("action:")) {
const url = new URL(actionRef);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(router.actionBase)) return;
function handleAnchor(evt) {
if (evt.defaultPrevented || evt.button !== 0 || evt.metaKey || evt.altKey || evt.ctrlKey || evt.shiftKey) return;
const a = evt.composedPath().find(el => el instanceof Node && el.nodeName.toUpperCase() === "A");
if (!a || explicitLinks && !a.getAttribute("link")) return;
const svg = isSvg(a);
const href = svg ? a.href.baseVal : a.href;
const target = svg ? a.target.baseVal : a.target;
if (target || !href && !a.hasAttribute("state")) return;
const rel = (a.getAttribute("rel") || "").split(/\s+/);
if (a.hasAttribute("download") || rel && rel.includes("external")) return;
const url = svg ? new URL(href, document.baseURI) : new URL(href);
if (url.origin !== window.location.origin || basePath && url.pathname && !url.pathname.toLowerCase().startsWith(basePath.toLowerCase())) return;
return [a, url];
}
const handler = actions.get(actionRef);
if (handler) {
function handleAnchorClick(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
const to = router.parsePath(url.pathname + url.search + url.hash);
const state = a.getAttribute("state");
evt.preventDefault();
const data = new FormData(evt.target);
handler.call(router, data);
navigateFromRoute(to, {
resolve: false,
replace: a.hasAttribute("replace"),
scroll: !a.hasAttribute("noscroll"),
state: state && JSON.parse(state)
});
}
}
function handleAnchorPreload(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
if (!preloadTimeout[url.pathname]) router.preloadRoute(url, a.getAttribute("preload") !== "false");
}
function handleAnchorIn(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [a, url] = res;
if (preloadTimeout[url.pathname]) return;
preloadTimeout[url.pathname] = setTimeout(() => {
router.preloadRoute(url, a.getAttribute("preload") !== "false");
delete preloadTimeout[url.pathname];
}, 200);
}
function handleAnchorOut(evt) {
const res = handleAnchor(evt);
if (!res) return;
const [, url] = res;
if (preloadTimeout[url.pathname]) {
clearTimeout(preloadTimeout[url.pathname]);
delete preloadTimeout[url.pathname];
}
}
function handleFormSubmit(evt) {
let actionRef = evt.submitter && evt.submitter.hasAttribute("formaction") ? evt.submitter.formAction : evt.target.action;
if (!actionRef) return;
if (!actionRef.startsWith("action:")) {
const url = new URL(actionRef);
actionRef = router.parsePath(url.pathname + url.search);
if (!actionRef.startsWith(actionBase)) return;
}
if (evt.target.method.toUpperCase() !== "POST") throw new Error("Only POST forms are supported for Actions");
const handler = actions.get(actionRef);
if (handler) {
evt.preventDefault();
const data = new FormData(evt.target);
handler.call(router, data);
}
}
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
document.addEventListener("mouseover", handleAnchorIn);
document.addEventListener("mouseout", handleAnchorOut);
document.addEventListener("focusin", handleAnchorPreload);
document.addEventListener("touchstart", handleAnchorPreload);
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
document.removeEventListener("mouseover", handleAnchorIn);
document.removeEventListener("mouseout", handleAnchorOut);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
document.removeEventListener("submit", handleFormSubmit);
});
// ensure delegated event run first
delegateEvents(["click", "submit"]);
document.addEventListener("click", handleAnchorClick);
if (preload) {
document.addEventListener("mouseover", handleAnchorIn);
document.addEventListener("mouseout", handleAnchorOut);
document.addEventListener("focusin", handleAnchorPreload);
document.addEventListener("touchstart", handleAnchorPreload);
}
document.addEventListener("submit", handleFormSubmit);
onCleanup(() => {
document.removeEventListener("click", handleAnchorClick);
if (preload) {
document.removeEventListener("mouseover", handleAnchorIn);
document.removeEventListener("mouseout", handleAnchorOut);
document.removeEventListener("focusin", handleAnchorPreload);
document.removeEventListener("touchstart", handleAnchorPreload);
}
document.removeEventListener("submit", handleFormSubmit);
});
};
}

@@ -1116,3 +1141,3 @@

init: notify => bindEvent(window, "popstate", () => notify()),
create: setupNativeEvents,
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
utils: {

@@ -1154,3 +1179,3 @@ go: delta => window.history.go(delta)

init: notify => bindEvent(window, "hashchange", () => notify()),
create: setupNativeEvents,
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
utils: {

@@ -1255,2 +1280,3 @@ go: delta => window.history.go(delta),

},
"link": "",
get ["aria-current"]() {

@@ -1257,0 +1283,0 @@ return isActive() ? "page" : undefined;

@@ -5,3 +5,2 @@ import type { Component, JSX } from "solid-js";

base?: string;
actionBase?: string;
root?: Component<RouteSectionProps>;

@@ -8,0 +7,0 @@ children?: JSX.Element;

@@ -6,6 +6,6 @@ /*@refresh skip*/

export const createRouterComponent = (router) => (props) => {
const { base, actionBase } = props;
const { base } = props;
const routeDefs = children(() => props.children);
const branches = createMemo(() => createBranches(props.root ? { component: props.root, children: routeDefs() } : routeDefs(), props.base || ""));
const routerState = createRouterContext(router, branches, { base, actionBase });
const routerState = createRouterContext(router, branches, { base });
router.create && router.create(routerState);

@@ -12,0 +12,0 @@ return (<RouterContextObj.Provider value={routerState}>

import type { JSX } from "solid-js";
import type { BaseRouterProps } from "./components";
export declare function hashParser(str: string): string;
export type HashRouterProps = BaseRouterProps;
export type HashRouterProps = BaseRouterProps & {
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function HashRouter(props: HashRouterProps): JSX.Element;

@@ -29,3 +29,3 @@ import { setupNativeEvents } from "../data/events";

init: notify => bindEvent(window, "hashchange", () => notify()),
create: setupNativeEvents,
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
utils: {

@@ -32,0 +32,0 @@ go: delta => window.history.go(delta),

@@ -5,3 +5,6 @@ import type { BaseRouterProps } from "./components";

url?: string;
actionBase?: string;
explicitLinks?: boolean;
preload?: boolean;
};
export declare function Router(props: RouterProps): JSX.Element;

@@ -23,3 +23,3 @@ import { isServer } from "solid-js/web";

init: notify => bindEvent(window, "popstate", () => notify()),
create: setupNativeEvents,
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
utils: {

@@ -26,0 +26,0 @@ go: delta => window.history.go(delta)

@@ -24,4 +24,3 @@ import { JSX, Accessor } from "solid-js";

base?: string;
actionBase?: string;
}): RouterContext;
export declare function createRouteContext(router: RouterContext, parent: RouteContext, outlet: () => JSX.Element, match: () => RouteMatch, params: Params): RouteContext;

@@ -234,3 +234,2 @@ import { createComponent, createContext, createMemo, createRenderEffect, createSignal, on, onCleanup, untrack, useContext, startTransition, resetErrorBoundaries } from "solid-js";

base: baseRoute,
actionBase: options.actionBase || "/_server",
location,

@@ -237,0 +236,0 @@ isRouting,

@@ -7,2 +7,3 @@ import type { Component, JSX, Signal } from "solid-js";

initialSubmission?: Submission<any, any>;
serverOnly?: boolean;
}

@@ -122,3 +123,2 @@ }

base: RouteContext;
actionBase: string;
location: Location;

@@ -125,0 +125,0 @@ navigatorFactory: NavigatorFactory;

@@ -9,3 +9,3 @@ {

"license": "MIT",
"version": "0.10.0-beta.8",
"version": "0.10.0-beta.9",
"homepage": "https://github.com/solidjs/solid-router#readme",

@@ -12,0 +12,0 @@ "repository": {

@@ -371,2 +371,10 @@ <p>

Cached function has a few useful methods for getting the key that are useful for invalidation.
```ts
let id = 5;
getUser.key // returns "users"
getUser.keyFor(id) // returns "users[5]"
```
This cache can be defined anywhere and then used inside your components with:

@@ -382,2 +390,4 @@

Using `cache` in `createResource` directly won't work properly as the fetcher is not reactive and it won't invalidate properly.
### `action`

@@ -396,3 +406,3 @@

// in component
<form action={myAction} />
<form action={myAction} method="post" />

@@ -403,2 +413,28 @@ //or

Actions only work with post requests, so make sure to put `method="post"` on your form.
Sometimes it might be easier to deal with typed data instead of `FormData` and adding additional hidden fields. For that reason Actions have a with method. That works similar to `bind` which applies the arguments in order.
Picture an action that deletes Todo Item:
```js
const deleteTodo = action(async (formData: FormData) => {
const id = Number(formData.get("id"))
await api.deleteTodo(id)
})
<form action={deleteUser} method="post">
<input type="hidden" name="id" value={todo.id} />
<button type="submit">Delete</button>
</form>
```
Instead with `with` you can write this:
```js
const deleteUser = action(api.deleteUser)
<form action={deleteUser.with(todo.id)} method="post">
<button type="submit">Delete</button>
</form>
```
#### Notes of `<form>` implementation and SSR

@@ -578,5 +614,18 @@ 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.

### `<Router>`
This is the main Router component for the browser.
| prop | type | description |
|-----|----|----|
| children | `JSX.Element` or `RouteDefinition[]` | The route definitions |
| root | Component | Top level layout comoponent |
| base | string | Base url to use for matching routes |
| actionBase | string | Root url for server actions, default: `/_server` |
| preload | boolean | Enables/disables preloads globally, default: `true` |
| explicitLinks | boolean | Disables all anchors being intercepted and instead requires `<A>`. default: `false` |
### `<A>`
Like the `<a>` tag but supports relative paths and active class styling.
Like the `<a>` tag but supports relative paths and active class styling (requires client side JavaScript).

@@ -737,5 +786,5 @@ The `<A>` tag has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendents (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.

## Migrations from 0.8.x
## Migrations from 0.9.x
v0.9.0 brings some big changes to support the future of routing including Islands/Partial Hydration hybrid solutions. Most notably there is no Context API available in non-hydrating parts of the application.
v0.10.0 brings some big changes to support the future of routing including Islands/Partial Hydration hybrid solutions. Most notably there is no Context API available in non-hydrating parts of the application.

@@ -754,3 +803,3 @@ The biggest changes are around removed APIs that need to be replaced.

These have been replaced by a load mechanism. This allows link hover preloads (as the load 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 load mechanism. This allows link hover preloads (as the load 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.

@@ -757,0 +806,0 @@ ## SPAs in Deployed Environments

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc