🎮 Beta Gamer

EventBus & hooks — React Native

React to game events without touching the socket directly. The EventBus is a typed singleton fed by all game hooks and board components automatically.

EventBus

Works anywhere in your app — inside or outside React components — as long as a game hook or board component is mounted and feeding events into it.

import { EventBus } from '@beta-gamer/react-native';

// Subscribe — returns an unsubscribe function
const unsub = EventBus.on('game:over', ({ winner, reason }) => {
  analytics.track('game_ended', { winner, reason });
});
unsub(); // remove listener

// Fire once then auto-remove
EventBus.once('game:started', ({ players }) => {
  console.log('game started with', players);
});

useEventBus()

Hook wrapper around EventBus. The on() it returns auto-cleans up when the component unmounts — no manual unsubscribe needed.

import { useEffect } from 'react';
import { useEventBus } from '@beta-gamer/react-native';

function GameOverlay() {
  const { on } = useEventBus();

  useEffect(() => {
    const unsub1 = on('game:started', ({ players }) => setPlayers(players));
    const unsub2 = on('game:over',    ({ winner })  => showResult(winner));
    return () => { unsub1(); unsub2(); };
  }, []);

  return null;
}

All events

EventPayloadGames
game:started{ roomId, playerId, players, currentTurn, ...gameSpecific }all
game:over{ winner: string | null, reason: string }all
game:move:made{ board, currentTurn, ...gameSpecific }all
afk:status{ playerId, expiresAt } | nullall
connection_error{ message: string }all
timer:update{ playerTimers: Record<string, number> }chess
chess:afk_warning{ playerId, secondsRemaining }chess
chess:afk_warning_clearedvoidchess
game:valid_moves{ position: number, moves: Move[] }checkers
checkers:afk_warning{ playerId, secondsRemaining }checkers
checkers:afk_warning_clearedvoidcheckers
connect4:afk_warning{ playerId, secondsRemaining }connect4
connect4:afk_warning_clearedvoidconnect4
tictactoe:afk_warning{ playerId, secondsRemaining }tictactoe
tictactoe:afk_warning_clearedvoidtictactoe
All payloads are fully typed via BetaGamerEvents. Import the type if needed: import type { BetaGamerEvents } from '@beta-gamer/react-native'

Other hooks

useSocket()

Returns the active socket from provider context — set by the provider (connectSocket=true) or registered by a game hook. May be null briefly on first render. Use when you need to emit custom events.

import { useSocket } from '@beta-gamer/react-native';

function ResignButton({ roomId, playerId }) {
  const socket = useSocket();
  return (
    <TouchableOpacity onPress={() => socket?.emit('game:resign', { roomId, playerId })}>
      <Text>Resign</Text>
    </TouchableOpacity>
  );
}

useConnectionError()

Returns the latest connection error as a string, or null. No built-in alert is shown — handle it yourself.

import { useConnectionError } from '@beta-gamer/react-native';

function GameUI() {
  const error = useConnectionError();
  if (error) return <Text style={{ color: 'red' }}>{error}</Text>;
  return <ChessBoard layout="default" onLeave={handleLeave} />;
}

useGameState()

Returns the provider-level game state — updated by game hooks via _updateGameState when game:over fires.

import { useGameState } from '@beta-gamer/react-native';

const { status, winner, reason } = useGameState();
// status: 'pending' | 'active' | 'ended'

useSession()

Returns the decoded JWT payload — game type, match type, players, theme, etc.

import { useSession } from '@beta-gamer/react-native';

const { game, matchType, players, theme, sessionId } = useSession();
Beta Gamer GaaS API — questions? support@beta-gamer.com