Skip to content

Commit 06c895d

Browse files
committedMar 1, 2023
fix: use experimental useEffectEvent
1 parent b2775cb commit 06c895d

9 files changed

+10688
-1047
lines changed
 

‎.eslintrc.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "react-app"
3+
}

‎package-lock.json

+10,585-943
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+7-4
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,19 @@
99
"preview": "vite preview"
1010
},
1111
"dependencies": {
12-
"react": "^18.2.0",
13-
"react-dom": "^18.2.0",
14-
"usehooks-ts": "^2.9.1"
12+
"react": "^0.0.0-experimental-6ff1733e6-20230225",
13+
"react-dom": "^0.0.0-experimental-6ff1733e6-20230225"
1514
},
1615
"devDependencies": {
1716
"@types/node": "^18.11.18",
1817
"@types/react": "^18.0.26",
1918
"@types/react-dom": "^18.0.9",
2019
"@vitejs/plugin-react-swc": "^3.0.0",
20+
"eslint": "^8.35.0",
21+
"eslint-config-react-app": "^7.0.1",
22+
"eslint-plugin-react-hooks": "^0.0.0-experimental-6ff1733e6-20230225",
2123
"typescript": "^4.9.3",
22-
"vite": "^4.0.0"
24+
"vite": "^4.0.0",
25+
"vite-plugin-eslint": "^1.8.1"
2326
}
2427
}

‎src/App.tsx

-8
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,18 @@
1-
import { useFetch } from "usehooks-ts";
21
import Wordle from "@components/Wordle";
3-
import Notification from "@components/Notification";
42
import Navigation from "@components/Navigation";
53
import "./App.css";
64

75
export default function App() {
8-
// const { data, error } = useFetch<string[]>(URL);
9-
10-
// const msg = !data ? (error ? "An error happened!" : "Fetching words...") : "";
11-
126
return (
137
<div className="App">
148
<Navigation>
159
<h1 className="logo">Wordle</h1>
1610
</Navigation>
17-
{/* {msg.length > 0 && <Notification>{msg}</Notification>} */}
1811
{DATA && <Wordle wordList={DATA} max_guesses={MAX_GUESSES} />}
1912
</div>
2013
);
2114
}
2215

23-
// const URL = `http://localhost:3000/solutions`;
2416
const MAX_GUESSES = 6;
2517

2618
const DATA = [

‎src/components/Row.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { HTMLAttributes, ReactNode } from "react";
1+
import { ReactNode } from "react";
22
import styles from "@components/Row.module.css";
33

44
export default function Row({ children, hasError }: Props) {

‎src/components/Wordle.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import Keyboard from "@components/Keyboard";
88

99
export default function Wordle({ wordList, max_guesses }: Props) {
1010
const [gameEvent, setGameEvent] = useState<GameEvent>(null);
11-
const { currentAttempt, guesses, keyStates, history, onKeyPress } =
11+
const { currentAttempt, guesses, keyStates, history, handleKeyPress } =
1212
useGuesses(max_guesses, wordList, (gameEvent) => setGameEvent(gameEvent));
1313

1414
const isInputDisabled =
1515
gameEvent?.type === "win" || gameEvent?.type === "game-over";
1616

17-
useKeyPress(onKeyPress, isInputDisabled);
17+
useKeyPress(handleKeyPress, isInputDisabled);
1818

1919
const hasError = gameEvent?.type === "error";
2020

@@ -36,7 +36,7 @@ export default function Wordle({ wordList, max_guesses }: Props) {
3636
/>
3737
<Keyboard
3838
keyStates={keyStates}
39-
onKeyPress={(key) => !isInputDisabled && onKeyPress(key)}
39+
onKeyPress={handleKeyPress}
4040
revealDelay={REVEAL_DELAY * 7}
4141
isInputDisabled={isInputDisabled}
4242
/>

‎src/hooks/useGuesses.ts

+79-84
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useRef, useCallback } from "react";
1+
import { useState, useRef } from "react";
22
import { Guess, State, GameEvent } from "@types";
33

44
export function useGuesses(
@@ -21,109 +21,104 @@ export function useGuesses(
2121
}))
2222
)
2323
);
24+
2425
const gameEventTimerId = useRef<number | null>(null);
2526

26-
const onKeyPress = useCallback(
27-
(keyValue: string) => {
28-
if (!isValidKey(keyValue)) return;
27+
function handleKeyPress(keyValue: string) {
28+
if (!isValidKey(keyValue)) return;
2929

30-
if (!isSpecialKey(keyValue)) {
31-
currentAttempt.length < solutionLength &&
32-
setCurrentAttempt(
33-
(prevCurrentGuess) =>
34-
prevCurrentGuess + keyValue.toLocaleLowerCase()
35-
);
36-
}
30+
if (!isSpecialKey(keyValue)) {
31+
currentAttempt.length < solutionLength &&
32+
setCurrentAttempt(
33+
(prevCurrentGuess) => prevCurrentGuess + keyValue.toLocaleLowerCase()
34+
);
35+
}
3736

38-
if (isDelete(keyValue)) {
39-
currentAttempt.length > 0 &&
40-
setCurrentAttempt((prevCurrentGuess) =>
41-
prevCurrentGuess.slice(0, -1)
42-
);
43-
}
37+
if (isDelete(keyValue)) {
38+
currentAttempt.length > 0 &&
39+
setCurrentAttempt((prevCurrentGuess) => prevCurrentGuess.slice(0, -1));
40+
}
4441

45-
if (isSubmit(keyValue)) {
46-
const canSubmitAttempt =
47-
history.length < max_turns &&
48-
!history.includes(currentAttempt) &&
49-
currentAttempt.length === solutionLength &&
50-
wordList.includes(currentAttempt);
51-
52-
if (!canSubmitAttempt) {
53-
let msg = "";
54-
let type = "error";
55-
56-
if (history.length >= max_turns) {
57-
msg = solution;
58-
type = "game-over";
59-
} else if (history.includes(currentAttempt)) {
60-
msg = "Already tried that!";
61-
} else if (currentAttempt.length !== solutionLength) {
62-
msg = "Not enough letters!";
63-
} else if (!wordList.includes(currentAttempt)) {
64-
msg = "Not in word list";
65-
}
66-
67-
onEvent({
68-
type,
69-
msg,
70-
} as GameEvent);
71-
72-
gameEventTimerId.current && clearTimeout(gameEventTimerId.current);
73-
gameEventTimerId.current = setTimeout(() => onEvent(null), 1200);
74-
75-
return;
42+
if (isSubmit(keyValue)) {
43+
const canSubmitAttempt =
44+
history.length < max_turns &&
45+
!history.includes(currentAttempt) &&
46+
currentAttempt.length === solutionLength &&
47+
wordList.includes(currentAttempt);
48+
49+
if (!canSubmitAttempt) {
50+
let msg = "";
51+
let type = "error";
52+
53+
if (history.length >= max_turns) {
54+
msg = solution;
55+
type = "game-over";
56+
} else if (history.includes(currentAttempt)) {
57+
msg = "Already tried that!";
58+
} else if (currentAttempt.length !== solutionLength) {
59+
msg = "Not enough letters!";
60+
} else if (!wordList.includes(currentAttempt)) {
61+
msg = "Not in word list";
7662
}
7763

78-
const currentGuess = toGuess(currentAttempt, solution);
64+
onEvent({
65+
type,
66+
msg,
67+
} as GameEvent);
7968

80-
setGuesses((prevGuesses) => {
81-
const newGuesses = [...prevGuesses] as Guess[][];
82-
newGuesses[history.length] = currentGuess;
83-
return newGuesses;
84-
});
69+
gameEventTimerId.current && clearTimeout(gameEventTimerId.current);
70+
gameEventTimerId.current = setTimeout(() => onEvent(null), 1200);
71+
72+
return;
73+
}
8574

86-
setKeyStates((prevKeyStates) => {
87-
const newKeyStates = { ...prevKeyStates };
88-
currentGuess.forEach(({ letter, state }) => {
89-
const _letter = letter!.toLocaleUpperCase();
90-
newKeyStates[_letter] = getFinalKeyState(
91-
newKeyStates[_letter],
92-
state
93-
);
94-
});
95-
96-
return newKeyStates;
75+
const currentGuess = toGuess(currentAttempt, solution);
76+
77+
setGuesses((prevGuesses) => {
78+
const newGuesses = [...prevGuesses] as Guess[][];
79+
newGuesses[history.length] = currentGuess;
80+
return newGuesses;
81+
});
82+
83+
setKeyStates((prevKeyStates) => {
84+
const newKeyStates = { ...prevKeyStates };
85+
currentGuess.forEach(({ letter, state }) => {
86+
const _letter = letter!.toLocaleUpperCase();
87+
newKeyStates[_letter] = getFinalKeyState(
88+
newKeyStates[_letter],
89+
state
90+
);
9791
});
9892

99-
setHistory((prevHistory) => [...prevHistory, currentAttempt]);
93+
return newKeyStates;
94+
});
10095

101-
history.length + 1 >= max_turns &&
102-
onEvent({
103-
type: "game-over",
104-
msg: solution,
105-
});
96+
setHistory((prevHistory) => [...prevHistory, currentAttempt]);
10697

107-
currentAttempt === solution &&
108-
onEvent({
109-
type: "win",
110-
msg: ["Impressive!", "Great!"].at(
111-
Math.floor(Math.random() * 2)
112-
) as string,
113-
});
98+
history.length + 1 >= max_turns &&
99+
onEvent({
100+
type: "game-over",
101+
msg: solution,
102+
});
114103

115-
setCurrentAttempt("");
116-
}
117-
},
118-
[currentAttempt, history, max_turns, solutionLength]
119-
);
104+
currentAttempt === solution &&
105+
onEvent({
106+
type: "win",
107+
msg: ["Impressive!", "Great!"].at(
108+
Math.floor(Math.random() * 2)
109+
) as string,
110+
});
111+
112+
setCurrentAttempt("");
113+
}
114+
}
120115

121116
return {
122117
currentAttempt,
123118
keyStates,
124119
guesses,
125120
history,
126-
onKeyPress,
121+
handleKeyPress,
127122
};
128123
}
129124

‎src/hooks/useKeyPress.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
import { useEffect } from "react";
1+
import {
2+
useEffect,
3+
experimental_useEffectEvent as useEffectEvent,
4+
} from "react";
25

36
// could use an effect event on onKeyPress
47
export function useKeyPress(
5-
onKeyPress: (keyPress: string) => void,
8+
handleKeyPress: (keyPress: string) => void,
69
isInputDisabled: boolean
710
) {
11+
const onKeyPress = useEffectEvent(handleKeyPress);
12+
813
useEffect(() => {
914
function handleKeyUp({ key }: KeyboardEvent) {
1015
!isInputDisabled && onKeyPress(key);
@@ -15,5 +20,5 @@ export function useKeyPress(
1520
return () => {
1621
window.removeEventListener("keyup", handleKeyUp);
1722
};
18-
}, [onKeyPress, isInputDisabled]);
23+
}, [isInputDisabled]);
1924
}

‎vite.config.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { defineConfig } from "vite";
22
import react from "@vitejs/plugin-react-swc";
3+
import eslint from "vite-plugin-eslint";
34
import path from "node:path";
45

56
// https://vitejs.dev/config/
67
export default defineConfig({
7-
plugins: [react()],
8+
plugins: [react(), eslint()],
89
resolve: {
910
alias: {
1011
"@hooks": path.resolve(__dirname, "./src/hooks"),

0 commit comments

Comments
 (0)
Please sign in to comment.