S
SolidJS3mo ago
J

Mutate a Resource after fetch efficiently when using <For>

Here's some "pseudo"code:
const [files, { refetch, mutate }]: Resource<File[] | undefined> = createResource(async () =>
await retrieveFiles(/* some path */)
);

// ...

async function onFileCreated(path: string) {
mutate([
...files,
...(await getFileMetadata(path)),
]);
}

// In a component:
<For each={files()!}>
// Omitted
</For>
const [files, { refetch, mutate }]: Resource<File[] | undefined> = createResource(async () =>
await retrieveFiles(/* some path */)
);

// ...

async function onFileCreated(path: string) {
mutate([
...files,
...(await getFileMetadata(path)),
]);
}

// In a component:
<For each={files()!}>
// Omitted
</For>
Now this works, however, anytime a file is created and mutate is called, For does not do any diffing and just goes through the arduous process of re-initializing every single DOM element it had already rendered. I have messed around with using this setup based off this Reddit thread from 2 years:
import { createDeepSignal } from "@solid-primitives/resource";

const [files, { refetch, mutate }] = createResource(async () =>
await retrieveFiles(/* some path */),
{
storage: createDeepSignal
}
);
import { createDeepSignal } from "@solid-primitives/resource";

const [files, { refetch, mutate }] = createResource(async () =>
await retrieveFiles(/* some path */),
{
storage: createDeepSignal
}
);
but to no avail. Whenever I call mutate my entire list which was rendered by <For> simply disappears. I honestly do not really understand what in the world createDeepSignal is supposed to do. The API seems extremely archaic. TLDR: I need a reactive resource that I can update with mutate, but that still has SolidJS's <For> diffing so the entire list isn't re-rendered when just one new item is added to the array. Also on a side note, can I pass multiple signals as a source to createResource? Based off the typedef (
export type ResourceSource<S> = S | false | null | undefined | (() => S | false | null | undefined);
export type ResourceSource<S> = S | false | null | undefined | (() => S | false | null | undefined);
) it would seem not, but that seems like a major oversight to me, is there seriously no way to pass an array of Accessors or something like that??
6 Replies
Brendonovich
Brendonovich3mo ago
The diffing <For> does is just based on the contents of the array since they're keyed by reference, so i'd guess the file objects are being recreated at some point. Also files is an accessor, so mutate([...files won't work - not sure if that was just a pseudocode thing A resource's source is just a function, you can provide a function that calls multiple signals and joins them together into one value
J
J3mo ago
mutate([...files was indeed a mistyping, I meant mutate([...files(), that should preserve the references, no?
Brendonovich
Brendonovich3mo ago
yeah it should
J
J3mo ago
Right, forgot about that Bugger So diffing has nothing to do with using stores? Let me check if I'm accidentally calling refetch
Brendonovich
Brendonovich3mo ago
with For i don't think so the store just gets iterated like a normal array and the item references are checked
J
J3mo ago
mutate seems to be triggering suspense which is entirely bizarre to me And I've confirmed that no refetching is being done Actually hold up lemme check 1 more thing Well whaddya know it is being refetched Sounds like a problem on my end Ah yeah so my fs event listener is also receiving modify events which was triggering a refetch Once again, really appreciate you helping me out brendonovich
Want results from more Discord servers?
Add your server