리펙토링: 코드 최적화
This commit is contained in:
@@ -12,12 +12,11 @@ import type {
|
||||
import FeedbackPanel from "@/components/game/FeedbackPanel";
|
||||
import ScoreSummary from "@/components/game/ScoreSummary";
|
||||
import StageIndicator from "@/components/game/StageIndicator";
|
||||
import { DESKTOP_INPUT_DEVICE_QUERY } from "@/lib/input-device";
|
||||
import KatexRenderer from "@/components/math/KatexRenderer";
|
||||
import { useGameStore } from "@/store/gameStore";
|
||||
import type { ProblemCount } from "@/store/gameStore";
|
||||
|
||||
const DESKTOP_INPUT_DEVICE_QUERY = "(any-hover: hover) and (any-pointer: fine)";
|
||||
const MOBILE_KEYBOARD_SPACER_OFFSET = 480;
|
||||
const REAL_NUMBER_PATTERN = /^-?\d+(?:\.\d+)?$/;
|
||||
|
||||
function parseAnswer(value: string) {
|
||||
@@ -44,14 +43,11 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
const resetSession = useGameStore((state) => state.resetSession);
|
||||
|
||||
const problemCardRef = useRef<HTMLDivElement>(null);
|
||||
const scrollTimeoutsRef = useRef<number[]>([]);
|
||||
const viewportResizeCleanupRef = useRef<(() => void) | null>(null);
|
||||
const answerFormRef = useRef<AnswerFormHandle>(null);
|
||||
|
||||
const [answerA, setAnswerA] = useState("");
|
||||
const [answerB, setAnswerB] = useState("");
|
||||
const [activeInput, setActiveInput] = useState<ActiveAnswerInput>(0);
|
||||
const [mobileFocusSpacerHeight, setMobileFocusSpacerHeight] = useState(0);
|
||||
const [inputError, setInputError] = useState("");
|
||||
|
||||
const sessionProblemCount = session?.problems.length ?? null;
|
||||
@@ -89,17 +85,6 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
setInputError("");
|
||||
}, [currentProblem?.key]);
|
||||
|
||||
const clearViewportFocusCleanup = useCallback(() => {
|
||||
scrollTimeoutsRef.current.forEach((timeoutId) => {
|
||||
window.clearTimeout(timeoutId);
|
||||
});
|
||||
scrollTimeoutsRef.current = [];
|
||||
viewportResizeCleanupRef.current?.();
|
||||
viewportResizeCleanupRef.current = null;
|
||||
}, []);
|
||||
|
||||
useEffect(() => clearViewportFocusCleanup, [clearViewportFocusCleanup]);
|
||||
|
||||
function handleSubmit(event: FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -124,10 +109,6 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
answerFormRef.current?.focusInput();
|
||||
}
|
||||
|
||||
const handleInputBlur = useCallback(() => {
|
||||
setMobileFocusSpacerHeight(0);
|
||||
}, []);
|
||||
|
||||
const scrollKatexToViewportTop = useCallback(() => {
|
||||
if (window.matchMedia(DESKTOP_INPUT_DEVICE_QUERY).matches) return;
|
||||
|
||||
@@ -157,53 +138,10 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
window.scrollTo(0, scrollTop);
|
||||
}
|
||||
|
||||
const visualViewport = window.visualViewport;
|
||||
const keyboardHeight = Math.max(
|
||||
0,
|
||||
window.innerHeight -
|
||||
(visualViewport?.height ?? window.innerHeight) -
|
||||
(visualViewport?.offsetTop ?? 0),
|
||||
);
|
||||
|
||||
setMobileFocusSpacerHeight(
|
||||
Math.max(
|
||||
window.innerHeight,
|
||||
keyboardHeight + MOBILE_KEYBOARD_SPACER_OFFSET,
|
||||
),
|
||||
);
|
||||
|
||||
clearViewportFocusCleanup();
|
||||
|
||||
if (visualViewport) {
|
||||
let settleTimeoutId: number | null = null;
|
||||
|
||||
const handleViewportResize = () => {
|
||||
if (settleTimeoutId !== null) {
|
||||
window.clearTimeout(settleTimeoutId);
|
||||
}
|
||||
|
||||
settleTimeoutId = window.setTimeout(() => {
|
||||
alignKatex();
|
||||
}, 180);
|
||||
};
|
||||
|
||||
visualViewport.addEventListener("resize", handleViewportResize);
|
||||
viewportResizeCleanupRef.current = () => {
|
||||
visualViewport.removeEventListener("resize", handleViewportResize);
|
||||
if (settleTimeoutId !== null) {
|
||||
window.clearTimeout(settleTimeoutId);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
window.requestAnimationFrame(alignKatex);
|
||||
});
|
||||
[900, 1300].forEach((delay) => {
|
||||
const timeoutId = window.setTimeout(alignKatex, delay);
|
||||
scrollTimeoutsRef.current.push(timeoutId);
|
||||
});
|
||||
}, [clearViewportFocusCleanup]);
|
||||
}, []);
|
||||
|
||||
if (!session || sessionNeedsInit) {
|
||||
return (
|
||||
@@ -284,7 +222,6 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
onActiveInputChange={setActiveInput}
|
||||
onAnswerAChange={setAnswerA}
|
||||
onAnswerBChange={setAnswerB}
|
||||
onInputBlur={handleInputBlur}
|
||||
onInputFocus={scrollKatexToViewportTop}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
@@ -298,13 +235,6 @@ export default function PlayClient({ problemCount }: PlayClientProps) {
|
||||
onNext={handleNextProblem}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{!submitted && mobileFocusSpacerHeight > 0 ? (
|
||||
<div
|
||||
aria-hidden="true"
|
||||
style={{ height: mobileFocusSpacerHeight }}
|
||||
/>
|
||||
) : null}
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user