Can I Pass `createAsync()` a Signal?

I'm building an analytics dashboard with the Plausible API. Their API let's you set the time period for the data you're requesting by appending a period value to your URL string like &period=6m0.
I want to dynamically change this period value when clicking buttons (e.g., "12mo", "month", "7day", etc). So my server function looks like this:
// This is very dumbed down for brevity
export async function getAggregateMetric(range: string) {
"use server";
await fetch(`https://plausible.io/api/v1/stats&perdiod=${range}`);
}
// This is very dumbed down for brevity
export async function getAggregateMetric(range: string) {
"use server";
await fetch(`https://plausible.io/api/v1/stats&perdiod=${range}`);
}
Here's my question. I'm using cache, createAsync() , and the load() function to render the initial data for the page. I'm setting a hard coded value for the first load. But after that I want to let users change the time period by clicking buttons. I've pasted my design pattern below. Is it a good pattern? I asking because I periodically get a page flicker or refresh when I click the buttons and I can't figure out why.
const getMetrics = cache(
async (range: string): Promise<AggregateResult | undefined> => {
"use server";
return await getAggregateMetrics(range);
},
"metrics"
);

// hard coded initial value
export const route = {
load() {
void getMetrics("6mo");
},
};

export default function AddNote() {
// hard coded initial value
const [range, setRange] = createSignal("6mo");
// using a signal here to force createAsync to rerun
const metrics = createAsync(() => getMetrics(range()));

function changeMetrics(newRange: string) {
setRange(newRange);
};

return (
<>
<h1>Metrics</h1>
<MetricsBar metrics={metrics}/>
<button onClick={() => changeMetrics("day")}>Day</button>
<button onClick={() => changeMetrics("6mo")}>6mo</button>
<button onClick={() => changeMetrics("12mo")}>12mo</button>
</>
);
}
const getMetrics = cache(
async (range: string): Promise<AggregateResult | undefined> => {
"use server";
return await getAggregateMetrics(range);
},
"metrics"
);

// hard coded initial value
export const route = {
load() {
void getMetrics("6mo");
},
};

export default function AddNote() {
// hard coded initial value
const [range, setRange] = createSignal("6mo");
// using a signal here to force createAsync to rerun
const metrics = createAsync(() => getMetrics(range()));

function changeMetrics(newRange: string) {
setRange(newRange);
};

return (
<>
<h1>Metrics</h1>
<MetricsBar metrics={metrics}/>
<button onClick={() => changeMetrics("day")}>Day</button>
<button onClick={() => changeMetrics("6mo")}>6mo</button>
<button onClick={() => changeMetrics("12mo")}>12mo</button>
</>
);
}
Thank you!
12 Replies
Brendonovich
Brendonovich3mo ago
This is a good design. The flicker is likely because metrics will trigger suspense each time it refetches, since setRange isn't wrapped in startTransition
ChrisThornham
ChrisThornhamOP3mo ago
Thank you! Is there a simple way to show me how to use startTransition?
Brendonovich
Brendonovich3mo ago
startTransition(() => setRange(newRange))
ChrisThornham
ChrisThornhamOP3mo ago
And that should fix the flicker?
Brendonovich
Brendonovich3mo ago
Should do
ChrisThornham
ChrisThornhamOP3mo ago
Brilliant! Thank you.
Brendonovich
Brendonovich3mo ago
It works since the createAsync will then re-run within that transition, so the UI will see the stale value rather than suspending
ChrisThornham
ChrisThornhamOP3mo ago
That works great! Is this the extent of the docs on startTransition? https://docs.solidjs.com/reference/reactive-utilities/start-transition#starttransition
Brendonovich
Brendonovich3mo ago
useTransition elaborates a bit more but yeah Could be useful to have a page dedicated to Transitions themselves
ChrisThornham
ChrisThornhamOP3mo ago
Haha. For people like myself who are still learning, definitely!
Brendonovich
Brendonovich3mo ago
Oh the solid tutorial has a section on them actually
ChrisThornham
ChrisThornhamOP3mo ago
Oh cool. I'll dig through that. Thanks! Just read about it. I get it now. That's a cool addition to the tool belt. Thanks again!
Want results from more Discord servers?
Add your server