-
Notifications
You must be signed in to change notification settings - Fork 635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add createQueryStore #6325
base: develop
Are you sure you want to change the base?
Add createQueryStore #6325
Conversation
… store methods from persisted state
if (activeRefetchTimeout) { | ||
clearTimeout(activeRefetchTimeout); | ||
activeRefetchTimeout = null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if i'm understanding correctly, you can only have one active refetch at a time. alternatively, could map queryKeys to timeoutIds and hold one for each query you want to poll.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
after taking a glance at your example, it seems stores might only get set up for a mutually exclusive queries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now it’s a query-per-store model — each query store operates independently, though a store's query params can be defined as dynamic subscriptions to any store’s state using the $
API.
It would be pretty straightforward to support multiple queries, since the caching system is already set up to handle multiple keys — just wanted to keep it simple initially and get all the core functionality working. I do think the single-query model may still be favorable since it encourages keeping stores small and modular, which helps limit serialization overhead.
* ```ts | ||
* const isInitialLoad = useQueryStore(state => state.getStatus().isInitialLoad); | ||
* ``` | ||
* @returns An object containing boolean flags for each status. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
curious why this is useful
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isInitialLoad
in particular or the whole status function?
Not sure I’ll keep either exactly as is currently. I think it’s all a bit redundant given status
and error
are exposed, and isInitialLoad
in most cases is essentially just the absence of data. It’s mainly for consistency with react-query — personally I’d rarely use these helpers.
On isInitialLoad
, you might want to for instance show a loading skeleton the first time the data loads (when there is no cached data), but not during refetches when cached data exists and can be displayed instead of a loading skeleton while new data is fetched.
…ocs, add overloads, misc. fixes
Fixes APP-2154
What changed (plus any additional context for devs)
createQueryStore
, which is a version ofcreateRainbowStore
with built-in fetching functionality, designed to be a more performant, more composable alternative touseQuery
, for most use casesuseQuery
→ Zustand sync pattern, which is inefficient and redundantMap
andSet
persistence support tocreateRainbowStore
partializer
tocreateRainbowStore
that automatically omits top-level store methods, which previously were being persisted whenpartialize
was not specifiedHow It Works
zustand-signal
. The$
function transforms a slice of a Zustand store into a liveAttachValue
. Under the hood, it’s a proxy that subscribes to changes in that slice of the store's state. When the specified state updates, the proxy immediately detects this, forcing the query store to recompute its internalqueryKey
based on the new params and refetch if needed.$
APIQueryStoreConfig
interfaceQueryStore
state interfaceNotes
set
andget
within the custom state creator currently are not aware of the query store's internal stateAbortController
support, to in certain cases actually terminate already-triggered fetches (for instance in the event a param rapidly changes twice)fetch
for data updatesstaleTime: Infinity
(first-time fetches will still occur)API Examples
The API In Its Simplest Form:
Dynamic
$
Params:Narrow state subscriptions linked directly to either internal or external store state.
No Params & Overriding Built-in Data Caching via
setData
:Screen recordings / screenshots
Two copies of the same query store implementation, each with their own state and a unique
address
param, both leveraging persistence and dynamic$
params (you wouldn't want two copies of the same store in practice, that's purely for testing purposes):ScreenRecording_12-23-2024.18-02-12_1.MP4
What to test