@@ -186,8 +186,8 @@ const todoCollection = createCollection(
186
186
queryCollectionOptions ({
187
187
queryKey: [" todoItems" ],
188
188
queryFn : async () => {
189
- const response = await fetch (" /api/todos" );
190
- return response .json ();
189
+ const response = await fetch (" /api/todos" )
190
+ return response .json ()
191
191
},
192
192
getKey : (item ) => item .id ,
193
193
schema: todoSchema , // any standard schema
@@ -301,7 +301,6 @@ This collection requires the following TrailBase-specific options:
301
301
302
302
A new collections doesn't start syncing until you call ` collection.preload() ` or you query it.
303
303
304
-
305
304
#### ` RxDBCollection `
306
305
307
306
[ RxDB] ( https://rxdb.info ) is a client-side database for JavaScript apps with replication, conflict resolution, and offline-first features.
@@ -335,7 +334,7 @@ await db.addCollections({
335
334
export const todoCollection = createCollection (
336
335
rxdbCollectionOptions ({
337
336
rxCollection: db .todos ,
338
- startSync: true
337
+ startSync: true ,
339
338
})
340
339
)
341
340
```
@@ -614,11 +613,11 @@ const addTodo = createOptimisticAction<string>({
614
613
body: JSON.stringify({ text, completed: false }),
615
614
})
616
615
const result = await response.json()
617
-
616
+
618
617
// IMPORTANT: Ensure server writes have synced back before returning
619
618
// This ensures the optimistic state can be safely discarded
620
619
await todoCollection.utils.refetch()
621
-
620
+
622
621
return result
623
622
},
624
623
})
@@ -671,47 +670,54 @@ When multiple mutations operate on the same item within a transaction, TanStack
671
670
672
671
The merging behavior follows a truth table based on the mutation types :
673
672
674
- | Existing → New | Result | Description |
675
- | -- - | -- - | -- - |
676
- | ** insert + update ** | ` insert ` | Keeps insert type , merges changes , empty original |
677
- | ** insert + delete ** | * removed * | Mutations cancel each other out |
678
- | ** update + delete ** | ` delete ` | Delete dominates |
679
- | ** update + update ** | ` update ` | Union changes , keep first original |
680
- | ** same type ** | * latest * | Replace with most recent mutation |
673
+ | Existing → New | Result | Description |
674
+ | ------------------ - | -------- - | ------------------------------------------------ - |
675
+ | ** insert + update ** | ` insert ` | Keeps insert type , merges changes , empty original |
676
+ | ** insert + delete ** | _removed_ | Mutations cancel each other out |
677
+ | ** update + delete ** | ` delete ` | Delete dominates |
678
+ | ** update + update ** | ` update ` | Union changes , keep first original |
679
+ | ** same type ** | _latest_ | Replace with most recent mutation |
681
680
682
681
#### Examples
683
682
684
683
** Insert followed by update :**
684
+
685
685
` ` ` ts
686
686
const tx = createTransaction({ autoCommit: false, mutationFn })
687
687
688
688
// Insert a new todo
689
- tx.mutate(() => todoCollection.insert({
690
- id: '1',
691
- text: 'Buy groceries',
692
- completed: false
693
- }))
689
+ tx.mutate(() =>
690
+ todoCollection.insert({
691
+ id: "1",
692
+ text: "Buy groceries",
693
+ completed: false,
694
+ })
695
+ )
694
696
695
697
// Update the same todo
696
- tx.mutate(() => todoCollection.update('1', (draft) => {
697
- draft.text = 'Buy organic groceries'
698
- draft.priority = 'high'
699
- }))
698
+ tx.mutate(() =>
699
+ todoCollection.update("1", (draft) => {
700
+ draft.text = "Buy organic groceries"
701
+ draft.priority = "high"
702
+ })
703
+ )
700
704
701
705
// Result: Single insert mutation with merged data
702
706
// { id: '1', text: 'Buy organic groceries', completed: false, priority: 'high' }
703
707
` ` `
704
708
705
709
** Insert followed by delete :**
710
+
706
711
` ` ` ts
707
712
// Insert then delete cancels out - no mutations sent to server
708
- tx.mutate(() => todoCollection.insert({ id: '1' , text: ' Temp todo' }))
709
- tx.mutate(() => todoCollection.delete('1' ))
713
+ tx.mutate(() => todoCollection.insert({ id: "1" , text: " Temp todo" }))
714
+ tx.mutate(() => todoCollection.delete("1" ))
710
715
711
716
// Result: No mutations (they cancel each other out)
712
717
` ` `
713
718
714
719
This intelligent merging ensures that :
720
+
715
721
- ** Network efficiency ** : Fewer mutations sent to the server
716
722
- ** User intent preservation ** : Final state matches what user expects
717
723
- ** Optimistic UI consistency ** : Local state always reflects user actions
@@ -899,32 +905,36 @@ import { queryCollectionOptions } from "@tanstack/query-db-collection"
899
905
900
906
// Load data into collections using TanStack Query.
901
907
// It's common to define these in a ` collections ` module.
902
- const todoCollection = createCollection(queryCollectionOptions({
903
- queryKey: ["todos"],
904
- queryFn: async () => fetch("/api/todos"),
905
- getKey: (item) => item.id,
906
- schema: todoSchema, // any standard schema
907
- onInsert: async ({ transaction }) => {
908
- const { changes: newTodo } = transaction.mutations[0]
909
-
910
- // Handle the local write by sending it to your API.
911
- await api.todos.create(newTodo)
912
- }
913
- // also add onUpdate, onDelete as needed.
914
- }))
915
- const listCollection = createCollection(queryCollectionOptions({
916
- queryKey: ["todo-lists"],
917
- queryFn: async () => fetch("/api/todo-lists"),
918
- getKey: (item) => item.id,
919
- schema: todoListSchema,
920
- onInsert: async ({ transaction }) => {
921
- const { changes: newTodo } = transaction.mutations[0]
922
-
923
- // Handle the local write by sending it to your API.
924
- await api.todoLists.create(newTodo)
925
- }
926
- // also add onUpdate, onDelete as needed.
927
- }))
908
+ const todoCollection = createCollection(
909
+ queryCollectionOptions({
910
+ queryKey: ["todos"],
911
+ queryFn: async () => fetch("/api/todos"),
912
+ getKey: (item) => item.id,
913
+ schema: todoSchema, // any standard schema
914
+ onInsert: async ({ transaction }) => {
915
+ const { changes: newTodo } = transaction.mutations[0]
916
+
917
+ // Handle the local write by sending it to your API.
918
+ await api.todos.create(newTodo)
919
+ },
920
+ // also add onUpdate, onDelete as needed.
921
+ })
922
+ )
923
+ const listCollection = createCollection(
924
+ queryCollectionOptions({
925
+ queryKey: ["todo-lists"],
926
+ queryFn: async () => fetch("/api/todo-lists"),
927
+ getKey: (item) => item.id,
928
+ schema: todoListSchema,
929
+ onInsert: async ({ transaction }) => {
930
+ const { changes: newTodo } = transaction.mutations[0]
931
+
932
+ // Handle the local write by sending it to your API.
933
+ await api.todoLists.create(newTodo)
934
+ },
935
+ // also add onUpdate, onDelete as needed.
936
+ })
937
+ )
928
938
929
939
const Todos = () => {
930
940
// Read the data using live queries. Here we show a live
@@ -935,19 +945,18 @@ const Todos = () => {
935
945
.join(
936
946
{ list: listCollection },
937
947
({ todo, list }) => eq(list.id, todo.list_id),
938
- ' inner'
948
+ " inner"
939
949
)
940
950
.where(({ list }) => eq(list.active, true))
941
951
.select(({ todo, list }) => ({
942
952
id: todo.id,
943
953
text: todo.text,
944
954
status: todo.status,
945
- listName: list.name
955
+ listName: list.name,
946
956
}))
947
957
)
948
958
949
959
// ...
950
-
951
960
}
952
961
` ` `
953
962
@@ -960,37 +969,41 @@ One of the most powerful ways of using TanStack DB is with a sync engine, for a
960
969
Here , we illustrate this pattern using [ElectricSQL ](https :// electric-sql.com) as the sync engine.
961
970
962
971
` ` ` tsx
963
- import type { Collection } from '@tanstack/db'
964
- import type { MutationFn, PendingMutation, createCollection } from '@tanstack/react-db'
965
- import { electricCollectionOptions } from '@tanstack/electric-db-collection'
966
-
967
- export const todoCollection = createCollection(electricCollectionOptions({
968
- id: 'todos',
969
- schema: todoSchema,
970
- // Electric syncs data using "shapes". These are filtered views
971
- // on database tables that Electric keeps in sync for you.
972
- shapeOptions: {
973
- url: 'https://api.electric-sql.cloud/v1/shape',
974
- params: {
975
- table: 'todos'
976
- }
977
- },
978
- getKey: (item) => item.id,
979
- schema: todoSchema,
980
- onInsert: async ({ transaction }) => {
981
- const response = await api.todos.create(transaction.mutations[0].modified)
972
+ import type { Collection } from "@tanstack/db"
973
+ import type {
974
+ MutationFn,
975
+ PendingMutation,
976
+ createCollection,
977
+ } from "@tanstack/react-db"
978
+ import { electricCollectionOptions } from "@tanstack/electric-db-collection"
982
979
983
- return { txid: response.txid}
984
- }
985
- // You can also implement onUpdate, onDelete as needed.
986
- }))
980
+ export const todoCollection = createCollection(
981
+ electricCollectionOptions({
982
+ id: "todos",
983
+ schema: todoSchema,
984
+ // Electric syncs data using "shapes". These are filtered views
985
+ // on database tables that Electric keeps in sync for you.
986
+ shapeOptions: {
987
+ url: "https://api.electric-sql.cloud/v1/shape",
988
+ params: {
989
+ table: "todos",
990
+ },
991
+ },
992
+ getKey: (item) => item.id,
993
+ schema: todoSchema,
994
+ onInsert: async ({ transaction }) => {
995
+ const response = await api.todos.create(transaction.mutations[0].modified)
996
+
997
+ return { txid: response.txid }
998
+ },
999
+ // You can also implement onUpdate, onDelete as needed.
1000
+ })
1001
+ )
987
1002
988
1003
const AddTodo = () => {
989
1004
return (
990
1005
<Button
991
- onClick={() =>
992
- todoCollection.insert({ text: "🔥 Make app faster" })
993
- }
1006
+ onClick={() => todoCollection.insert({ text: "🔥 Make app faster" })}
994
1007
/>
995
1008
)
996
1009
}
@@ -1009,7 +1022,7 @@ npm install react-native-random-uuid
1009
1022
Then import it at the entry point of your React Native app (e .g ., in your ` App.js ` or ` index.js ` ):
1010
1023
1011
1024
` ` ` javascript
1012
- import ' react-native-random-uuid'
1025
+ import " react-native-random-uuid"
1013
1026
` ` `
1014
1027
1015
1028
This polyfill provides the ` crypto.randomUUID() ` function that TanStack DB uses internally for generating unique identifiers.
0 commit comments