前提・実現したいこと
ReactでWebのタイピングアプリを製作したく、Codesandboxにて少しずつコードを書いています。
現在は、タイピングが完了した前の単語に戻るボタンを設置しようとしているのですが、
問題が発生したため、お力添えをいただけませんでしょうか。
下記がCodesandboxのリンクとなります。
https://codesandbox.io/s/typing-test-fgzfr?file=/src/App.tsx:0-3080
※プログラミング歴がまだ2か月のため、的外れな文章や汚いコード(全然typescriptの書き方じゃないなど)恐縮です。
発生している問題・エラーメッセージ
・「前の単語に戻る」ための戻るボタンを押した際に、先の単語に進んでしまうことがある。
・一度戻るボタンを使用すると、タイピング完了時に「次の単語に進む」メソッドが実行された際にも、前の単語に戻ってしまうことがある。
該当のソースコード
React typescript
import React, { useState, useEffect, useRef } from "react"; import "./App.scss"; export default function App() { //問題例 const wordList = [ "tora", "raion", "ookami", "baison", "kitsune", "usagi", "inu", "neko", "ningen", "hitsuji" ]; //ルビ const rubiList = [ "とら", "らいおん", "おおかみ", "ばいそん", "きつね", "うさぎ", "いぬ", "ねこ", "にんげん", "ひつじ" ]; //漢字 const anserList = [ "虎", "ライオン", "狼", "バイソン", "狐", "ウサギ", "犬", "猫", "人間", "羊" ]; //タイピングに関する部分 const [number, setNumber] = useState(1); const [anser, setAnser] = useState(anserList[0]); const [rubi, setRubi] = useState(rubiList[0]); const [text, setText] = useState(wordList[0]); const [position, setPosition] = useState(0); const [typo, setTypo] = useState(new Array(0)); const handleKey = (e: React.KeyboardEvent<HTMLDivElement>) => { // 文字の配列を取得 let textSpans = document.querySelector("#textbox").children; // 入力したキーと現在入力しようとしている文字が一致するとき if (e.key === text[position]) { // 現在の文字を入力済とする textSpans[position].className = "typed-letters"; textSpans[position].classList.remove("current-letter"); // まだ入力していない文字があるとき if (position <= text.length - 2) { // 次の位置へ移動 textSpans[position + 1].className = "current-letter"; setPosition(position + 1); // 全ての文字を入力し終わったとき } else { setNumber(number + 1); setText(wordList[number]); setAnser(anserList[number]); setRubi(rubiList[number]); setPosition(0); textSpans[0].className = "current-letter"; for (let i = 1; i < text.length; i++) { textSpans[i].className = " waiting-letters"; console.log(number); } } // 間違ったキーを入力したとき } else { if (typo.indexOf(position) === -1) { setTypo([...typo, position]); textSpans[position].classList.add("typo"); } } }; //入力エリアにフォーカスを当てる const searchInput = useRef(null); useEffect(() => { searchInput.current.focus(); }); //戻るボタン const backButton = () => { setNumber(number - 1); setText(wordList[number]); setAnser(anserList[number]); setRubi(rubiList[number]); setPosition(0); console.log(number); }; return ( <> <div ref={searchInput} className="App" onKeyPress={(e) => handleKey(e)} tabIndex={0} > <h1> {/* 問題(漢字) */} <ruby> {anser} <rt>{rubi}</rt> </ruby> </h1> {/* 入力部分 */} <div id="textbox"> <span className="current-letter">{text[0]}</span> {text .split("") .slice(1) .map((char) => ( <span className="waiting-letters">{char}</span> ))} </div> {/* 戻るボタン */} <button onClick={() => { backButton(); }} > 戻る </button> </div> </> ); }
試したこと
再レンダリングのために問題が発生しているのかと思い、memoやcallbackを使用してみましたが、解決できませんでした(やり方が間違っていた可能性はありますが...)。
なお、将来的にはRailsの中に埋め込む形で使用したいと考えているので、rooterは使用しないでこの中で完結する形で単語の遷移がしたいです。
もしお気づきのことがございましたら、ご教授いただけますと幸いです。
宜しくお願い致します。
補足情報(FW/ツールのバージョンなど)
下記がCodesandboxのリンクとなります。
https://codesandbox.io/s/typing-test-fgzfr?file=/src/App.tsx:0-3080
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/09/03 12:08