New in version 0.8.23.
Defining a subclass of rx.SharedState creates a special type of state that may be shared by multiple clients. Shared State is useful for creating real-time collaborative applications where multiple users need to see and interact with the same data simultaneously.
An rx.SharedState subclass behaves similarly to a normal rx.State subclass and will be private to each client until it is explicitly linked to a given token. Once linked, any changes made to the Shared State by one client will be propagated to all other clients sharing the same token.
An rx.SharedState subclass can be linked to a token using the _link_to method, which is async and returns the linked state instance. After linking, subsequent events triggered against the shared state will be executed in the context of the linked state. To unlink from the token, return the result of awaiting the _unlink method.
To try out the collaborative counter example, open this page in a second or third browser tab and click the "Link" button. You should see the count increment in all tabs when you click the "Increment" button in any of them.
Collaborative Count: 0
Each client linked to a shared state can be uniquely identified by their self.router.session.client_token. Shared state events should never rely on identifiers passed in as parameters, as these can be spoofed from the client. Instead, always use the client_token to identify the client triggering the event.
Shared Room
Users:
An rx.SharedState subclass has two attributes for determining link status and peers, which are updated during linking and unlinking, and come with some caveats.
_linked_to: str
Provides the token that the state is currently linked to, or empty string if not linked.
This attribute is only set on the linked state instance returned by _link_to. It will be an empty string on any unlinked shared state instances. However, if another state links to a client's private token, then the _linked_to attribute will be set to the client's token rather than an empty string.
When _linked_to equals self.router.session.client_token, it is assumed that the current client is unlinked, but another client has linked to this client's private state. Although this is possible, it is generally discouraged to link shared states to private client tokens.
_linked_from: set[str]
A set of client tokens that are currently linked to this shared state instance.
This attribute is only updated during _link_to and _unlink calls. In situations where unlinking occurs otherwise, such as client disconnects, self.reset() is called, or state expires on the backend, _linked_from may contain stale client tokens that are no longer linked. These can be cleaned periodically by checking if the tokens still exist in app.event_namespace.token_to_sid.
When defining a shared state, aim to keep it as minimal as possible. Only include the data and methods that need to be shared between clients. This helps reduce complexity and potential synchronization issues.
Linked states are always loaded into the tree for each event on each linked client and large states take longer to serialize and transmit over the network. Because linked states are regularly loaded in the context of many clients, they incur higher lock contention, so minimizing loading time also reduces lock waiting time for other clients.
A shared state should primarily use backend-only vars (prefixed with an underscore) to store shared data. Often, not all users of the shared state need visibility into all of the data in the shared state. Use computed vars to provide sanitized access to shared data as needed.
If certain data in the shared state needs to be personalized for each user, prefer to expose that data through computed vars defined in private states. This allows each user to have their own view of the shared data without exposing sensitive information to other users. It also reduces the amount of unrelated data sent to each client and improves caching performance by keeping each user's view cached in their own private state, rather than always recomputing the shared state vars for each user that needs to have their information updated.
Use async computed vars with get_state to access shared state data from private states.
It is often convenient to define dynamic routes that include the linked token as part of the URL path. This allows users to easily share links to specific shared state instances. The dynamic route can use on_load to link the shared state to the token extracted from the URL.