Store utilities
Store utilities provide access to RTK queries for interacting with configured data sources
import store from "operations/store";This is how custom code reads and writes data without a surrounding list screen. It is most useful on custom pages, which have no data plumbing of their own.
const {
useGetListQuery,
useLazyGetListQuery,
useGetItemQuery,
useLazyGetItemQuery,
useNewItemMutation,
useUpdateItemMutation,
useDeleteItemMutation,
} = store.getApi();Call
store.getApi()inside your component body, not at module top level.
These are RTK Query hooks: queries return { data, currentData, error, isLoading, isFetching, isSuccess, refetch }, mutations return [trigger, { data, isLoading, isSuccess, error }] and lazy queries return [trigger, result] where trigger(arg).unwrap() gives a promise.
Results are cached and shared across the whole application, so asking for the same data twice does not cause two requests.
Listing records
const { data, isFetching } = useGetListQuery(
{ source: "product", type: "list" },
{ refetchOnMountOrArgChange: true }
);
// data → { list: [{ id, data, … }], totalCount }source
required, the data source id
type
"list" for a plain listing, "query" for a filtered/paginated one. Default "list"
params
becomes the query string. Array values are sent as array parameters
payload
request body, for sources listed via POST
method
override the source's configured method
path
appended to the listing URL
versionId
see the caveat below
Pass { skip: !ready } to defer a query until its input is available.
Filtered query versioning
A plain type: "list" query refreshes automatically after any create, update or delete on that source.
A type: "query" query only does so if you give it a versionId. Without one it will happily serve stale results after a save. Generate one per query:
Reading one record
Use
currentData, notdata, whenever you useskip.datakeeps the previous argument's result while the new one loads.
Creating, updating, deleting
All three refresh the affected lists and record automatically, including in other browser tabs. Pass skipInvalidate: true if you deliberately want to suppress that.
Full update vs partial update
updateItem chooses between sending the whole record and sending only the changed fields. It sends the whole record when there are many changes, when a changed value is itself an object (a partial update cannot express removals), or when the source does not support partial updates.
You can force it: force: "set" always sends the full record, force: "patch" always sends only the changes.
changes uses the same shape the platform's change tracking produces:
Version conflicts
On sources with version validation, saving a record someone else has changed in the meantime fails with error === "VERSION_CONFLICT" rather than a normal error.
A standard editor handles this for you by showing a conflict dialog with force and merge options. If you write your own save path, you have to handle it yourself. At minimum, tell the user and reload the record.
Other errors come back as { status, message, code, data }.
Last updated
