diff --git a/package-lock.json b/package-lock.json
index a0df879..22b0b94 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,7 +18,7 @@
"random-words": "^1.1.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
- "react-scripts": "5.0.1",
+ "react-scripts": "^5.0.1",
"react-select": "^5.3.0",
"react-toastify": "^10.0.4",
"styled-components": "^5.3.5",
diff --git a/package.json b/package.json
index 5676514..9bd499f 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,7 @@
"random-words": "^1.1.2",
"react": "^18.0.0",
"react-dom": "^18.0.0",
- "react-scripts": "5.0.1",
+ "react-scripts": "^5.0.1",
"react-select": "^5.3.0",
"react-toastify": "^10.0.4",
"styled-components": "^5.3.5",
diff --git a/src/App.js b/src/App.js
index d5c2f3f..9a01e91 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,28 +1,31 @@
-import React, { useState, useRef, useEffect } from "react";
+import React, { useState, Suspense, useRef, useEffect } from "react";
import { ThemeProvider } from "styled-components";
import { defaultTheme, themesOptions } from "./style/theme";
import { GlobalStyles } from "./style/global";
-import TypeBox from "./components/features/TypeBox/TypeBox";
-import SentenceBox from "./components/features/SentenceBox/SentenceBox";
-import Logo from "./components/common/Logo";
-import MusicPlayerSnackbar from "./components/features/MusicPlayer/MusicPlayerSnackbar";
-import FooterMenu from "./components/common/FooterMenu";
-import FreeTypingBox from "./components/features/FreeTypingBox";
+
import {
GAME_MODE,
GAME_MODE_DEFAULT,
GAME_MODE_SENTENCE,
} from "./constants/Constants";
import useLocalPersistState from "./hooks/useLocalPersistState";
-import DefaultKeyboard from "./components/features/Keyboard/DefaultKeyboard";
-import WordsCard from "./components/features/WordsCard/WordsCard";
import {
SOUND_MODE,
soundOptions,
DEFAULT_SOUND_TYPE,
DEFAULT_SOUND_TYPE_KEY,
} from "./components/features/sound/sound";
-import DynamicBackground from "./components/common/DynamicBackground";
+
+// Lazy load components to boost performance
+const TypeBox = React.lazy(() => import('./components/features/TypeBox/TypeBox'));
+const SentenceBox = React.lazy(() => import('./components/features/SentenceBox/SentenceBox'));
+const Logo = React.lazy(() => import('./components/common/Logo'));
+const MusicPlayerSnackbar = React.lazy(() => import('./components/features/MusicPlayer/MusicPlayerSnackbar'));
+const FooterMenu = React.lazy(() => import('./components/common/FooterMenu'));
+const FreeTypingBox = React.lazy(() => import('./components/features/FreeTypingBox'));
+const WordsCard = React.lazy(() => import('./components/features/WordsCard/WordsCard'));
+const DefaultKeyboard = React.lazy(() => import('./components/features/Keyboard/DefaultKeyboard'));
+const DynamicBackground = React.lazy(() => import('./components/common/DynamicBackground'));
function App() {
// localStorage persist theme setting
@@ -174,7 +177,7 @@ function App() {
return (
- <>
+
@@ -245,7 +248,7 @@ function App() {
onMouseLeave={() => focusTextInput()}
>
- >
+
);
}
diff --git a/src/components/common/DynamicBackground.js b/src/components/common/DynamicBackground.js
index fd78fcc..0faf48b 100644
--- a/src/components/common/DynamicBackground.js
+++ b/src/components/common/DynamicBackground.js
@@ -24,4 +24,4 @@ const DynamicBackground = ({ theme }) => {
return null;
};
-export default DynamicBackground;
+export default React.memo(DynamicBackground);
diff --git a/src/components/common/FooterMenu.js b/src/components/common/FooterMenu.js
index 6ee1ad9..efd3ad9 100644
--- a/src/components/common/FooterMenu.js
+++ b/src/components/common/FooterMenu.js
@@ -253,4 +253,4 @@ const FooterMenu = ({
);
};
-export default FooterMenu;
+export default React.memo(FooterMenu);
diff --git a/src/components/common/Logo.js b/src/components/common/Logo.js
index 45598f0..d423f12 100644
--- a/src/components/common/Logo.js
+++ b/src/components/common/Logo.js
@@ -15,4 +15,4 @@ const Logo = ({ isFocusedMode }) => {
);
};
-export default Logo;
+export default React.memo(Logo);
diff --git a/src/components/features/FreeTypingBox.js b/src/components/features/FreeTypingBox.js
index bfc87ac..cd010bb 100644
--- a/src/components/features/FreeTypingBox.js
+++ b/src/components/features/FreeTypingBox.js
@@ -51,4 +51,4 @@ const FreeTypingBox = ({ spaces = 4, textAreaRef, soundMode, soundType }) => {
);
};
-export default FreeTypingBox;
+export default React.memo(FreeTypingBox);
diff --git a/src/components/features/Keyboard/DefaultKeyboard.js b/src/components/features/Keyboard/DefaultKeyboard.js
index 63e83eb..8c40d19 100644
--- a/src/components/features/Keyboard/DefaultKeyboard.js
+++ b/src/components/features/Keyboard/DefaultKeyboard.js
@@ -222,4 +222,4 @@ const DefaultKeyboard = ({soundType, soundMode}) => {
);
};
-export default DefaultKeyboard;
+export default React.memo(DefaultKeyboard);
diff --git a/src/components/features/SentenceBox/SentenceBox.js b/src/components/features/SentenceBox/SentenceBox.js
index 7c7df70..34b80b3 100644
--- a/src/components/features/SentenceBox/SentenceBox.js
+++ b/src/components/features/SentenceBox/SentenceBox.js
@@ -1,5 +1,4 @@
-import React from "react";
-import { useState, useMemo, useEffect } from "react";
+import React, {useCallback, useMemo, useEffect, useState} from "react";
import { sentencesGenerator } from "../../../scripts/sentencesGenerator";
import { Stack } from "@mui/material";
import { Grid } from "@mui/material";
@@ -168,25 +167,31 @@ const SentenceBox = ({
extra: 0,
});
- const checkAndUpdateStats = (currSentence, currInput) => {
- const newStats = stats;
+const checkAndUpdateStats = useCallback((currSentence, currInput) => {
+ setStats((prevStats) => {
+ let correct = prevStats.correct;
+ let incorrect = prevStats.incorrect;
+ let extra = prevStats.extra;
+
for (let i = 0; i < currSentence.length; i++) {
if (currSentence[i] === currInput[i]) {
- newStats.correct++;
+ correct++;
} else {
- newStats.incorrect++;
+ incorrect++;
}
}
+
const deltaCharDifference = currInput.length - currSentence.length;
if (deltaCharDifference > 0) {
- newStats.extra = deltaCharDifference;
+ extra = deltaCharDifference;
}
- setStats(newStats);
- };
+ return { correct, incorrect, extra };
+ });
+}, []);
- const handleKeyDown = (e) => {
+ const handleKeyDown = useCallback(() => (e) => {
if (status !== "finished" && soundMode) {
play();
}
@@ -208,7 +213,7 @@ const SentenceBox = ({
return;
}
- setRawKeyStroke(rawKeyStroke + 1);
+ setRawKeyStroke(prevRawKeyStroke => prevRawKeyStroke + 1);
// if enter key pressed.
// advance to next sentence only if the input val length is equal to the current sentence char count);
@@ -221,14 +226,14 @@ const SentenceBox = ({
setTimeRunning(false);
return;
}
- setCurrSentenceIndex(currSentenceIndex + 1);
+ setCurrSentenceIndex(prevCurrSentenceIndex => prevCurrSentenceIndex + 1);
setCurrInput("");
sentenceInputRef.current.value = "";
return;
}
return;
}
- };
+ });
const getCharClassName = (idx, char) => {
if (idx < currInput.length) {
@@ -268,14 +273,14 @@ const SentenceBox = ({
}
};
- const handleChange = (e) => {
+ const handleChange = useCallback(() => (e) => {
const {
currentTarget: { value },
} = e;
if (e.currentTarget instanceof HTMLInputElement && !isOnComposition) {
setCurrInput(value);
}
- };
+ });
return (
@@ -452,4 +457,4 @@ const SentenceBox = ({
);
};
-export default SentenceBox;
+export default React.memo(SentenceBox);
diff --git a/src/components/features/SentenceBox/SentenceBoxStats.js b/src/components/features/SentenceBox/SentenceBoxStats.js
index 58c6df8..b6e61fd 100644
--- a/src/components/features/SentenceBox/SentenceBoxStats.js
+++ b/src/components/features/SentenceBox/SentenceBoxStats.js
@@ -43,4 +43,4 @@ const SentenceBoxStats = ({ status, wpm, countDown, stats, rawKeyStrokes }) => {
);
};
-export default SentenceBoxStats;
+export default React.memo(SentenceBoxStats);
diff --git a/src/components/features/TypeBox/Stats.js b/src/components/features/TypeBox/Stats.js
index 10d1a81..3aee333 100644
--- a/src/components/features/TypeBox/Stats.js
+++ b/src/components/features/TypeBox/Stats.js
@@ -47,4 +47,4 @@ const Stats = ({
);
};
-export default Stats;
+export default React.memo(Stats);
diff --git a/src/components/features/TypeBox/TypeBox.js b/src/components/features/TypeBox/TypeBox.js
index ac5963f..7e36416 100644
--- a/src/components/features/TypeBox/TypeBox.js
+++ b/src/components/features/TypeBox/TypeBox.js
@@ -991,4 +991,4 @@ const TypeBox = ({
);
};
-export default TypeBox;
+export default React.memo(TypeBox);
diff --git a/src/components/features/WordsCard/WordsCard.js b/src/components/features/WordsCard/WordsCard.js
index f3ae6c1..b2691fd 100644
--- a/src/components/features/WordsCard/WordsCard.js
+++ b/src/components/features/WordsCard/WordsCard.js
@@ -1,5 +1,4 @@
-import React from "react";
-import { useState, useEffect, useRef } from "react";
+import React, { useState, useCallback, useEffect, useRef } from "react";
import { DICTIONARY_SOURCE_CATALOG } from "../../../constants/DictionaryConstants";
import {
RECITE_MODE_TITLE,
@@ -100,11 +99,11 @@ const WordsCard = ({ soundType, soundMode }) => {
}
};
- const handleInputChange = (e) => {
+ const handleInputChange = useCallback(() => (e) => {
setCurrInput(e.target.value);
hiddenInputRef.current.value = e.target.value;
e.preventDefault();
- };
+ });
const updateAlphabetSet = (char) => {
const newAlphabetSet = new Set(alphabetSet);
@@ -516,4 +515,4 @@ const WordsCard = ({ soundType, soundMode }) => {
);
};
-export default WordsCard;
+export default React.memo(WordsCard);
diff --git a/src/components/utils/Select.js b/src/components/utils/Select.js
index 50be847..f84daa0 100644
--- a/src/components/utils/Select.js
+++ b/src/components/utils/Select.js
@@ -54,4 +54,4 @@ export default styled(Select)`
background: ${({ theme }) => theme.background};
}
-`;
\ No newline at end of file
+`;
diff --git a/src/scripts/wordsGenerator.js b/src/scripts/wordsGenerator.js
index f9d8ff2..8fdf336 100644
--- a/src/scripts/wordsGenerator.js
+++ b/src/scripts/wordsGenerator.js
@@ -139,6 +139,6 @@ const wordsCardVocabGenerator = (vocabSource, chapter) => {
wordsList.push(VOCAB_DICTIONARIES[vocabSource][i]);
}
return wordsList;
-};
+}
export { wordsGenerator, chineseWordsGenerator, wordsCardVocabGenerator };