Storage allows us to create persistent data that multiple users can edit simultaneously. This is ideal for storing realtime document state, such as shapes on a canvas, paragraphs in a text editor, or cells in a spreadsheet.
Storage is part of our Realtime APIs product.
To build applications using storage, you can make use of our conflict-free data types. Each type is similar to a JavaScript counterpart:
LiveObject
- JavaScript ObjectLiveList
- JavaScript ArrayLiveMap
- JavaScript MapThese data types can be combined and nested, to create a realtime data structure that automatically updates when multiple users modify data at the same time, whilst handling any conflicts along the way.
Let’s imagine we were storing some data about a person, for example their name and age.
person: { name: "Marie", age: 30 }
To add this to storage, first we must define our types. Open
liveblocks.config.ts
and use a LiveObject
with the structure for
person
as a generic.
/liveblocks.config.ts
// Storage typeStorage: { person: LiveObject<{ name: string; age: number; }>;}
Now we’ve defined the type, we can switch to App.tsx
and add an
intialStorage
value, that is used when the room’s storage is created. We can
match the Storage
type by creating a new LiveObject
.
/App.tsx
<RoomProvider id={roomId} initialStorage={{ person: new LiveObject({ name: "Marie", age: 30 }), }}>
Using a LiveObject like this, instead of a regular JavaScript object, allows us to use its realtime features. For example multiple people can edit the properties of a LiveObject at the same time without overriding the whole object.
To use this realtime data in your app, we can import a hook named
useStorage
. This hook allows us to select part of our storage, before
returning its value, and automatically updating on realtime changes.
// { person: "Marie", age: 30 }const person = useStorage((root) => root.person);
Each realtime data structure is converted to an immutable copy of its
JavaScript counterpart, so a LiveObject
becomes a regular JavaScript object.
We can implement this ourselves by adding the following code to Room.tsx
:
/Room.tsx
import { useStorage } from "@liveblocks/react/suspense";
export function Room() { const person = useStorage((root) => root.person);
return <div>Person: {JSON.stringify(person)}</div>;}
If we weren’t using suspense
in our config file, person
would return null
until it was loaded, and we’d have to check for this. We’re using suspense
here, so this isn’t a worry.
Press the refresh button in the preview window to reload initialStorage
,
and you should now be seeing person
! On the next page we’ll be updating
storage.