@robojs/sync - `useSyncBroadcast` and `useSyncContext` hooks
Points: 5
These new hooks are intended to bring about a new Context System.
Essentially, each namespace (dependency array) may have a context, not just state. It can be used to listen to client events connected to the same key. Since we'd have all clients in the same context, that would also allow us to broadcast arbitrary payloads.
Context System
The existing useSyncState would be modified to return a third variable:
const [status, setStatus, statusContext ] = useSyncState('winning', ['status'])
The statusContext object would include the following fields:
- clients: An array of active clients connected with the same dependency array.
- clientId: The unique identifier for the current client.
- isHost: A boolean indicating if the current client is the host or initiator.
- metadata: Any additional metadata associated with the synchronization context.
- on: Function to register event handlers.
Proposed type signature:
interface SyncContext<ClientData = unknown> {
clients: Client<ClientData>[]
clientId: string
isHost: boolean
metadata?: Record<string, unknown>
on?: (event: string, (client: Client<ClientData>) => void) => void
}
interface Client<ClientData = any> {
id: string
data?: ClientData // e.g., user info
}
Example usage:
import { useSyncState } from '@robojs/sync'
export function MultiplayerGame() {
const [gameState, setGameState, syncContext] = useSyncState(initialGameState, ['gameRoom'])
const { clients, clientId, isHost, broadcast } = syncContext
// Use the context to implement custom logic
useEffect(() => {
if (isHost) {
// Perform host-specific initialization
}
}, [isHost])
const handlePlayerAction = (action) => {
// Update the game state locally
setGameState((prev) => ({ ...prev, ...action }))
// Broadcast the action to other clients
broadcast(action)
}
return (
<div>
<GameBoard state={gameState} onAction={handlePlayerAction} />
<div>Connected Players: {clients.length}</div>
</div>
)
}
useSyncBroadcast
This new hook would allow receiving and sending direct broadcasts to other clients in the same dependency array, or both.
It returns a context object and accepts a function as the first argument. The callback receives the payload and context as arguments. Think of it as a useEffect without the boilerplate.
const { broadcast, context, send } = useSyncBroadcast((message: string, context) => {
console.log(context.client.id, 'said', message)
}, ['status'])
Result object includes:
- broadcast: A function to send messages or updates to all connected clients.
- context: The context for the dependency array.
- send: A function to send a message or update to a specific client.
useSyncContext
Can be used to get the context of a dependency array easily.
const context = useSyncContext(['status'])
It can optionally accept an object as an optional first item for convenience callbacks:
useSyncContext({
onConnect: (client) => console.log(client.id, ‘has left’),
onDisconnect: (client) => console.log(client.id, ‘has joined’)
}, [‘status’])
Hi @Pkmmte,
I’d love to work on this issue. Could you please assign it to me? As I’m new to this repository, I’d also appreciate any guidance to help me get started.
Hi @Rishi-0007
Thank you for your interest in contributing to Robo! This issue was initially tagged as a good first issue, but we then found it involves some deeper integrations that might be challenging as an initial task. In particular due to the way our server and core framework interact with this plugin's websocket connections.
I recommend looking at issue #331 instead, which could be a great place to start. It's more tailored to new contributors and should help you get acquainted with our codebase. I’ve added more details on the exact file to modify and am here (and on Discord) to provide any guidance you need to get started.
Feel free to ask any questions!