Game hooks — React Native
Each board component is powered by a game hook internally. You can call the hook directly to build a fully custom board UI, or pass it to a board component to share the socket.
Available hooks
| Hook | Game |
|---|---|
| useChessGame() | Chess |
| useCheckersGame() | Checkers |
| useConnect4Game() | Connect 4 |
| useTictactoeGame() | Tic-tac-toe |
Each hook connects to the game server, handles matchmaking, and returns all the state you need to render a board. They also feed events into the EventBus automatically.
Three ways to use them
1. Just the board — no hook needed
The board calls the hook internally. Simplest option.
<ChessBoard layout="default" onLeave={handleLeave} />2. Hook + board — shared socket, access to state
Call the hook yourself, pass it to the board. One socket, full state access.
const game = useChessGame();
// Read anything from the hook
console.log(game.isMyTurn, game.players, game.fen, game.clocks);
// Board uses your hook instance — no duplicate socket
<ChessBoard game={game} layout="board-only" onLeave={handleLeave} />3. Hook only — fully custom board UI
Skip the board component entirely. Build your own UI with the hook's state and handlers.
import { BetaGamerProvider, useChessGame } from '@beta-gamer/react-native';
import { View, TouchableOpacity, Text } from 'react-native';
function MyCustomChessBoard() {
const {
chess, fen, selected, legalMoves, lastMove,
isMyTurn, myColor, players, clocks,
handleSquarePress, gameOver, gameResult,
} = useChessGame();
const files = ['a','b','c','d','e','f','g','h'];
const ranks = [8,7,6,5,4,3,2,1];
return (
<View>
{ranks.map(rank => (
<View key={rank} style={{ flexDirection: 'row' }}>
{files.map(file => {
const square = `${file}${rank}`;
const piece = chess.get(square);
const isSelected = selected === square;
const isLegal = legalMoves.includes(square);
const isLastMove = lastMove?.from === square || lastMove?.to === square;
return (
<TouchableOpacity
key={square}
onPress={() => handleSquarePress(square)}
style={{
width: 44, height: 44,
backgroundColor: isSelected ? '#7C3AED'
: isLegal ? '#4ADE80'
: isLastMove ? '#FCD34D'
: (file.charCodeAt(0) + rank) % 2 === 0 ? '#B58863' : '#F0D9B5',
alignItems: 'center', justifyContent: 'center',
}}
>
{piece && <Text style={{ fontSize: 28 }}>{pieceEmoji(piece)}</Text>}
</TouchableOpacity>
);
})}
</View>
))}
<Text style={{ color: '#9CA3AF', marginTop: 8 }}>
{gameOver ? (gameResult?.winner ? 'Game over' : 'Draw') : isMyTurn ? 'Your turn' : "Opponent's turn"}
</Text>
</View>
);
}
function pieceEmoji({ type, color }: { type: string; color: string }) {
const map: Record<string, string> = { p: color === 'w' ? '♙' : '♟', r: color === 'w' ? '♖' : '♜', n: color === 'w' ? '♘' : '♞', b: color === 'w' ? '♗' : '♝', q: color === 'w' ? '♕' : '♛', k: color === 'w' ? '♔' : '♚' };
return map[type] ?? '';
}
export function GameScreen({ sessionToken }) {
return (
<BetaGamerProvider token={sessionToken} connectSocket={false}>
<MyCustomChessBoard />
</BetaGamerProvider>
);
}useChessGame() return value
| Field | Type | Description |
|---|---|---|
| socket | Socket | null | The active socket.io socket |
| roomId | string | null | Current room ID (set after game:started) |
| myPlayerId | string | Your player ID assigned by the server |
| myColor | "white" | "black" | Your assigned color |
| fen | string | Current board position in FEN notation |
| chess | Chess | chess.js instance — use for move validation, piece lookup, etc. |
| currentTurn | number | Index into players[] of whose turn it is |
| players | any[] | Both players (set after game:started) |
| clocks | { self: number; opponent: number } | Remaining time in seconds |
| selected | string | null | Currently selected square (e.g. "e2") |
| legalMoves | string[] | Legal destination squares for selected piece |
| lastMove | { from: string; to: string } | null | Last move made |
| moveHistory | { san: string }[] | Full move history in algebraic notation |
| promotionMove | { from: string; to: string } | null | Set when a pawn promotion is pending |
| isMyTurn | boolean | Whether it is your turn |
| gameOver | boolean | True after game ends (with 400ms delay) |
| gameResult | { winner: string | null; reason: string } | null | Set when game ends |
| afkWarning | { playerId: string; secondsRemaining: number } | null | AFK countdown state |
| handleSquarePress | (square: string) => void | Call on square tap — handles selection and move emission |
| emitMove | (from, to, promotion?) => void | Emit a move directly (used for promotion) |
| setPromotionMove | (m | null) => void | Clear or set the pending promotion move |
Note:
useCheckersGame, useConnect4Game, and useTictactoeGame follow the same pattern with game-specific fields (e.g. board, validMoves, winningLine). See the game-specific docs in the sidebar for their full return values.Beta Gamer GaaS API — questions? support@beta-gamer.com