Skip to content

Instantly share code, notes, and snippets.

@cray0000
Last active November 16, 2018 18:31
Show Gist options
  • Save cray0000/534efd859f5d6ff6e398b6d754183fcc to your computer and use it in GitHub Desktop.
Save cray0000/534efd859f5d6ff6e398b6d754183fcc to your computer and use it in GitHub Desktop.
react-sharedb HOOKS
import React from 'react'
import {useDoc, useQuery, useLocal, useValue, useSubscribe} from 'react-sharedb'
export function Simple ({gameId}) {
let [game, $game] = useDoc('games', gameId)
if (!game) return null // <Loading />
function updateGameTitle (event) {
$game.set('title', event.target.value)
}
return (
<div>
<h1>{game.title}</h1>
<label>
Edit game title:
<input type='text' value={game.title} onChange={updateGameTitle} />
</label>
</div>
)
}
export function MultipleSubscribeWaves ({gameId}) {
let [secret, $secret] = useValue('My Secret')
let [userId, $userId] = useLocal('_session.userId')
let [user, $user] = useDoc('users', userId)
let [game, $game] = useDoc('games', gameId)
if (!(game && user)) return null // <Loading />
let [players, $players] = useQuery('players', {_id: {$in: game.playerIds}})
if (!players) return null // <Loading />
let [users, $users] = useQuery('users', {_id: {$in: players.map(i => i.userId)}})
if (!users) return null // <Loading />
function updateSecret (event) {
$secret.set(event.target.value)
}
function updateName (event) {
$user.set('name', event.target.value)
}
return (
<div>
<label>
Secret:
<input type='text' vaule={code} onChange={updateSecret} />
</label>
<label>
My User Name:
<input type='text' value={user.name} onChange={updateName} />
</label>
<h1>Game {game.title}</h1>
<h2>Users in game:</h2>
<p>{users.map(i => i.name).join(', ')}</p>
</div>
)
}
export function MultipleSubscribeWavesUseSubscribe ({gameId}) {
let {
ready
secret, $secret,
userId,
user, $user,
game,
players,
users
} = useSubscribe(() => ({
secret: useValue('My Secret'),
userId: useLocal('_session.userId'),
user: useDoc('users', userId),
game: useDoc('games', gameId)
}), () => ({
players: useQuery('players', {_id: {$in: game.playerIds}})
}), () => ({
users: useQuery('users', {_id: {$in: players.map(i => i.userId)}})
}))
if (!ready) return null // <Loading />
function updateSecret (event) {
$secret.set(event.target.value)
}
function updateName (event) {
$user.set('name', event.target.value)
}
return (
<div>
<label>
Secret:
<input type='text' vaule={code} onChange={updateSecret} />
</label>
<label>
My User Name:
<input type='text' value={user.name} onChange={updateName} />
</label>
<h1>Game {game.title}</h1>
<h2>Users in game:</h2>
<p>{users.map(i => i.name).join(', ')}</p>
</div>
)
}
// This is a documented verison of the first example
export function Simple ({gameId}) {
// Subscribe to `game` from mongo. You have to explicitely wait for all `useDoc` and `useQuery` to finish
let [game, $game] = useDoc('games', gameId)
// Wait for `game` subscription to finish
if (!game) return null // <Loading />
function updateGameTitle (event) {
$game.set('title', event.target.value)
}
return (
<div>
<h1>{game.title}</h1>
<label>
Edit game title:
<input type='text' value={game.title} onChange={updateGameTitle} />
</label>
</div>
)
}
export function MultipleSubscribeWaves ({gameId}) {
// Private value, which lives only in this component's private scope model (`$store`)
let [secret, $secret] = useValue('My Secret')
// Get userId from local path `_session.userId` (synchronous).
let [userId, $userId] = useLocal('_session.userId')
// And then subscribe to this user's document by id from mongo.
// Since it might get data from mongo, this operation is async, so we need to wait until it completes
//
// You have to explicitely wait for any asynchronous subscription (`useDoc`, `useQuery`) to finish.
// Otherwise you will end up with the "can't read `foo` of undefined" errors.
// While the subscription didn't finish, the data returned from the `useDoc` and `useQuery` is just an `[]`.
let [user, $user] = useDoc('users', userId)
// We have to wait for `user` subscription to finish, but the next subscription we are going to do (`game`)
// does not depend on `user`. So to make subscriptions finish faster, lets subscribe to `game` right away.
// And then we'll wait for both -- the `user` and the `game` subscriptions to finish.
// Subscribe to the game document from mongo (async).
// This subscription will start in parallel to our `user` subscription.
let [game, $game] = useDoc('games', gameId)
// Wait for both `game` and `user` subscriptions to finish
if (!(game && user)) return null // <Loading />
// Subscribe to all players in the game. We take `playerIds` data from the previous subscription,
// that's why we had to wait for the `game` to finish first and can't just subscribe to `players` in parallel.
let [players, $players] = useQuery('players', {_id: {$in: game.playerIds}})
// Wait for `players` since for next subscription we'll have to use it
if (!players) return null // <Loading />
// Subscribe to each player's user document.
let [users, $users] = useQuery('users', {_id: {$in: players.map(i => i.userId)}})
// Wait for all the remaining subscriptions before proceeding to the render code.
if (!users) return null // <Loading />
function updateSecret (event) {
$secret.set(event.target.value)
}
function updateName (event) {
$user.set('name', event.target.value)
}
return (
<div>
<label>
Secret:
<input type='text' vaule={code} onChange={updateSecret} />
</label>
<label>
My User Name:
<input type='text' value={user.name} onChange={updateName} />
</label>
<h1>Game {game.title}</h1>
<h2>Users in game:</h2>
<p>{users.map(i => i.name).join(', ')}</p>
</div>
)
}
export function MultipleSubscribeWavesUseSubscribe ({gameId}) {
// Same subscriptions as in previous component, but using a single useSubscribe hook,
// which also lets you wait for everything using the `ready` magic flag.
let {
ready
secret, $secret,
userId,
user, $user,
game,
players,
users
} = useSubscribe(() => ({
secret: useValue('My Secret'),
userId: useLocal('_session.userId'),
user: useDoc('users', userId),
game: useDoc('games', gameId)
}), () => ({
players: useQuery('players', {_id: {$in: game.playerIds}})
}), () => ({
users: useQuery('users', {_id: {$in: players.map(i => i.userId)}})
}))
if (!ready) return null // <Loading />
function updateSecret (event) {
$secret.set(event.target.value)
}
function updateName (event) {
$user.set('name', event.target.value)
}
return (
<div>
<label>
Secret:
<input type='text' vaule={code} onChange={updateSecret} />
</label>
<label>
My User Name:
<input type='text' value={user.name} onChange={updateName} />
</label>
<h1>Game {game.title}</h1>
<h2>Users in game:</h2>
<p>{users.map(i => i.name).join(', ')}</p>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment