-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusePlayer.ts
80 lines (68 loc) · 2.43 KB
/
usePlayer.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import { useCallback, useContext, useRef, useState } from 'react';
import GameContext from '../context/GameContext';
import { getNextPlayer } from '../controllers/playerController';
import { IPlayerResult, TUsePlayer } from '../utils/types';
/**
* A React hook that gets result {@link IPlayerResult} from players and record it as a last action of player.
*
* usePlayer hook provides three important callback functions 'play', 'nextPlayer' and 'addWord'.
*
* @func usePlayer
* @memberOf React
* @return {TUsePlayer} - Returns {@link player} for play again and switch the current user,
* a callback{@link addWord} that waits an input from players, {@link lastAction} that contains last action of a player.
*/
const usePlayer = (): TUsePlayer => {
const { state, dispatch } = useContext(GameContext);
// Hosts 'play' Promise resolve.
const resolveRef = useRef<(value: IPlayerResult) => void>();
const [lastAction, setLastAction] = useState<IPlayerResult>();
// Switches between players.
const nextPlayer = () => {
const player = getNextPlayer(state.currentPlayer, state.players);
dispatch({ type: 'currentPlayer', payload: player });
};
/** *
* Waits a new response from user and updates 'lastAction' ONLY if 'addWord' callback
* is provided with a result {@link IPlayerResult} by players.
* Saves last action as the Promise resolves.
*
* Promise resolve logic extracted for several reasons;
* to create a very simple React based event like result-waiting trigger.
* to prevent unnecessary renders
* to extract promise outside of the hook and delivers it to players as an act of providence.
*
* Once 'play' function is triggered, 'addWord' callback already waiting for a response will be reactivated
* @memberOf usePlayer
* @function
* @inner
*/
const play = async () => {
const result = await new Promise((resolve: (value: IPlayerResult) => void) => {
resolveRef.current = resolve;
});
setLastAction(result);
};
/**
* This function has only one purpose. Resolves 'play' Promise with the result {@link IPlayerResult}
* once called from anywhere.
* @memberOf usePlayer
* @function
* @inner
*/
const addWord = useCallback(
(result: IPlayerResult) => {
resolveRef.current?.(result);
},
[resolveRef.current],
);
return {
player: {
play,
nextPlayer,
},
addWord,
lastAction,
};
};
export default usePlayer;