T
TanStack4w ago
fascinating-indigo

React best practices (context vs hook)

Is there an accepted or recommended best practice when it comes to reusing collection/mutation logic with TanStack DB and React? For instance, while migrating my app from Query to DB, I wrote this at first:
export const useBlock = (id: string) => {
const { blocks } = useCollections(); // defines all my collections
const query = useLiveQuery((q) =>
q
.from({ block: blocks })
.where(({ block }) => eq(block.id, id))
.findOne()
);

return {
block: query.data,
updateTitle: (title: string) =>
blocks.update(id, (draft) => {
draft.title = title;
}),
};
};
export const useBlock = (id: string) => {
const { blocks } = useCollections(); // defines all my collections
const query = useLiveQuery((q) =>
q
.from({ block: blocks })
.where(({ block }) => eq(block.id, id))
.findOne()
);

return {
block: query.data,
updateTitle: (title: string) =>
blocks.update(id, (draft) => {
draft.title = title;
}),
};
};
Now I'm trying to understand whether the hook is a good enough approach or if a context is better since I'll be using this useBlock hook in a variety of places. Does useLiveQuery already optimize for that under the hood?
6 Replies
correct-apricot
correct-apricot4w ago
You should generally reuse collections to avoid reloading data etc There's a small cost to setting up new live queries (generally at most a ms or so) but it doesn't hurt to reuse them for sure
fascinating-indigo
fascinating-indigoOP4w ago
oh yeah forgot to mention useCollections does pull from a context. might as well put live queries in relevant contexts too. thanks!
optimistic-gold
optimistic-gold3w ago
hey I'm v curious what this context looks like! do you do the same const someCollection = createCollection({...}) in a useEffect and return some memoised map like { some: someCollection, other: otherCollection } ? and then that effect just never re-runs? or only when you log in/out? (My AI helper is telling me to use a singleton pattern for a collections object that i initialize out of react scope, and then an initialize function in the same file that modifies it directly! wild. it seems familiar-ish from when I have played with stores/svelte things... but it's not an approach I've used before.)
fascinating-indigo
fascinating-indigoOP3w ago
i’m currently refactoring that into a more resilient approach but yeah basically the memoized one you mentioned first i’ll try to remember to come back here and post my updated solution, but i wrote a Syncable class that i then subclass for each entity/model type in my app to try to get an api closer to Linear’s (https://github.com/wzhudev/reverse-linear-sync-engine) so now the collections go into a model registry (outside of react) and i initialize that in a useEffect that runs whenever queryClient changes (should happen once only)
GitHub
GitHub - wzhudev/reverse-linear-sync-engine: A reverse engineering ...
A reverse engineering of Linear's sync engine. Endorsed by its co-founder & CTO. - wzhudev/reverse-linear-sync-engine
optimistic-gold
optimistic-gold3w ago
oh I am already using Zustand for something else here... I could initialize them in a zustand store and access them like this... 🤔 it has a nice imperative init() approach
rival-black
rival-black3w ago
Yup, I'm doing similar using jotai.

Did you find this page helpful?