S
SolidJS•4w ago
rtzrtz.

SingleFlight does not work (See Example)

I'm trying to make a single flight request work, but I'm always getting two requests: What am I missing here?
import {
action,
createAsync,
query,
revalidate,
useAction,
} from "@solidjs/router";

const items: string[] = ["yo", "lo", "foo", "bar"];

const getItems = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 200));
return items;
}, "items");

const addAction = action(async (item: string) => {
"use server";
items.push(item);
return revalidate("items");
});

export default function Flight() {
const items = createAsync(async () => getItems(), { // does always fire after clicking "Add"
deferStream: true,
});

const addItem = useAction(addAction); // response never includes items-data

return (
<div>
<ul>
{items()?.map((item) => (
<li>{item}</li>
))}
</ul>
<button onClick={() => addItem(Date.now().toString())}>Add</button>
</div>
);
}
import {
action,
createAsync,
query,
revalidate,
useAction,
} from "@solidjs/router";

const items: string[] = ["yo", "lo", "foo", "bar"];

const getItems = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 200));
return items;
}, "items");

const addAction = action(async (item: string) => {
"use server";
items.push(item);
return revalidate("items");
});

export default function Flight() {
const items = createAsync(async () => getItems(), { // does always fire after clicking "Add"
deferStream: true,
});

const addItem = useAction(addAction); // response never includes items-data

return (
<div>
<ul>
{items()?.map((item) => (
<li>{item}</li>
))}
</ul>
<button onClick={() => addItem(Date.now().toString())}>Add</button>
</div>
);
}
4 Replies
Brendonovich
Brendonovich•4w ago
Try doing createAsync(() => getItems() and using reload instead of revalidate - revalidate is basically just for client use though i will mention using const items as shared state isn't entirely reliable, there will be a few copies of it on the server that may not be producing the behaviour you expect
rtzrtz.
rtzrtz.OP•4w ago
Thank you! I changed it to this, still the same behaviour. 😦
import { action, createAsync, query, reload, useAction } from "@solidjs/router";

const items: string[] = ["yo", "lo", "foo", "bar"];

const getItems = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 200));
return items;
}, "items");

const addAction = action(async (item: string) => {
"use server";
items.push(item);
return reload();
});

export default function Flight() {
const items = createAsync(() => getItems(),{
deferStream: true,
});

const addItem = useAction(addAction);

return (
<div>
<ul>
{items()?.map((item) => (
<li>{item}</li>
))}
</ul>
<button onClick={() => addItem(Date.now().toString())}>Add</button>
</div>
);
}
import { action, createAsync, query, reload, useAction } from "@solidjs/router";

const items: string[] = ["yo", "lo", "foo", "bar"];

const getItems = query(async () => {
"use server";
await new Promise((r) => setTimeout(r, 200));
return items;
}, "items");

const addAction = action(async (item: string) => {
"use server";
items.push(item);
return reload();
});

export default function Flight() {
const items = createAsync(() => getItems(),{
deferStream: true,
});

const addItem = useAction(addAction);

return (
<div>
<ul>
{items()?.map((item) => (
<li>{item}</li>
))}
</ul>
<button onClick={() => addItem(Date.now().toString())}>Add</button>
</div>
);
}
though i will mention using const items as shared state isn't entirely reliable, there will be a few copies of it on the server that may not be producing the behaviour you expect
Haha of course, this is just for the minimal prototype here. But either way, items are getting fetched - and I understand SingleFlight would return that fetch with the action-response directly, right?
Brendonovich
Brendonovich•4w ago
Oh actually SFM relies on you providing a preload function for the route It executes the preloads for the route after the action
rtzrtz.
rtzrtz.OP•4w ago
ohhh, that makes sense thats missing in the docs 😄 it works now, thank you! 🙂 In case anyone runs into the same issue, here is a working, minimal example. 🙂
import {
action,
createAsync,
query,
RouteDefinition,
useAction,
} from "@solidjs/router";

const getDate = query(async () => {
"use server";
return new Date().toISOString();
}, "items");

const addAction = action(async () => {
"use server";
// something that might affect the date, who knows
return;
});

export const route = {
preload() {
getDate();
},
} satisfies RouteDefinition;

export default function Flight() {
const date = createAsync(() => getDate(), {
deferStream: true,
});

const someMutation = useAction(addAction);

return (
<div>
<p>{date()}</p>
<button onClick={someMutation}>Add</button>
</div>
);
}
import {
action,
createAsync,
query,
RouteDefinition,
useAction,
} from "@solidjs/router";

const getDate = query(async () => {
"use server";
return new Date().toISOString();
}, "items");

const addAction = action(async () => {
"use server";
// something that might affect the date, who knows
return;
});

export const route = {
preload() {
getDate();
},
} satisfies RouteDefinition;

export default function Flight() {
const date = createAsync(() => getDate(), {
deferStream: true,
});

const someMutation = useAction(addAction);

return (
<div>
<p>{date()}</p>
<button onClick={someMutation}>Add</button>
</div>
);
}

Did you find this page helpful?