質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

Q&A

0回答

1036閲覧

react nativeでクイズをランダムかつ重複させないで表示する方法がわかりません

A.K

総合スコア0

React Native

React Nativeは、ネイティブモバイルアプリ(iOS/Android)を作成できるJavaScriptフレームワークです。Reactと同じ設計のため、宣言的なコンポーネントでリッチなUIを開発することが可能です。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

0グッド

0クリップ

投稿2020/12/28 12:51

前提・実現したいこと

ここに質問の内容を詳しく書いてください。
React native で 4択クイズのアプリを作っています。
クイズをランダムかつ重複しないように表示させたいです。
ランダム表示は成功しましたが、どうしても同じクイズが表示され重複してしまいます。
以下のソースコードからどのように重複せずにクイズを表示させることが出来るのかわかりません。
React Native や Type Scriptについて全くの初心者であるため、迷走中です。
どなたかご教授宜しくお願いいたします。

発生している問題・エラーメッセージ

エラーは出ていません。

該当のソースコード

export function App() {

const questions = [
{
questionText: "mouth",
answerOptions: [
{ answerText: "目", isCorrect: false },
{ answerText: "顔", isCorrect: false },
{ answerText: "口", isCorrect: true },
{ answerText: "耳", isCorrect: false },
],
},
{
questionText: "eyebrow",
answerOptions: [
{ answerText: "胸", isCorrect: false },
{ answerText: "お腹", isCorrect: false },
{ answerText: "眉毛", isCorrect: true },
{ answerText: "耳", isCorrect: false },
],
},
{
questionText: "knee",
answerOptions: [
{ answerText: "腕", isCorrect: false },
{ answerText: "肩", isCorrect: false },
{ answerText: "膝", isCorrect: true },
{ answerText: "肘", isCorrect: false },
],
},
{
questionText: "elbow",
answerOptions: [
{ answerText: "背中", isCorrect: false },
{ answerText: "手", isCorrect: false },
{ answerText: "肘", isCorrect: true },
{ answerText: "首", isCorrect: false },
],
},
];

const randomQuestions =
questions[Math.floor(Math.random() * questions.length)];

return (
<View style={styles.container}>

<Text style={styles.question}> {randomQuestions.questionText} </Text> <Text style={styles.answer}> {randomQuestions.answerOptions[0].answerText} </Text> <Text style={styles.answer}> {randomQuestions.answerOptions[1].answerText} </Text> <Text style={styles.answer}> {randomQuestions.answerOptions[2].answerText} </Text> <Text style={styles.answer}> {randomQuestions.answerOptions[3].answerText} </Text> </View> );

};

react native``` ### 試したこと クイズを重複しないように試したことが、 「空の配列を作り、配列の中に同じ数字がなければ配列にpushし、その後spliceで削除する」といったことも試しました。 pushした際、(例えばランダムの数字が1なら)空の配列に[1]と入るのですが、次の問題にいったとき、「配列がまた空に戻りそこからランダムの数字が入れられる」ということが起こるため、再度ランダムの数字に1が選ばれることがあります。(よってクイズが重複します) 以下が試したコードです。 const randomQuiz: number[] = []; const min = 0; const max = questions.length; function intRandom(min: number, max: number) { return Math.floor(Math.random() * (max - min)) + min; } for (let i = min; i < max; i++) { while (true) { let tmp = intRandom(min, max); if (!randomQuestions.includes(tmp)) { randomQuestions.push(tmp); randomQuestions.splice(tmp); break; } } } ### 補足情報(FW/ツールのバージョンなど) 使っているツールは、macで、ソフトは Visual Studio Code です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2020/12/28 13:08

「試したこと」でお書きになった配列を、App コンポーネントの state にする必要がありますが、React の state の扱いはご存知でしょうか?
A.K

2020/12/28 13:41

回答有難うございます。 stateは少し使ったことがありますが「試したこと」のコードにstateを使う方法が思い浮かびません。 考えてみたのですが、以下のようなコードだとどうでしょか? 宜しくお願いいたします。 const [randomQuestions, setRandomQuestions] = useState([]); const randomQuiz: number[] = []; const min = 0; const max = questions.length; function intRandom(min: number, max: number) { return Math.floor(Math.random() * (max - min)) + min; } for (let i = min; i < max; i++) { while (true) { let tmp = intRandom(min, max); if (!randomQuestions.includes(tmp)) { randomQuestions.push(tmp); randomQuestions.splice(tmp); setRandomQuestions(randomQuiz); break; } } }
hoshi-takanori

2020/12/28 14:15

見落としてましたが、次の問題を表示するのはどうやってますか? イベント処理のコードがないので、たぶんリロードしてるんじゃないかと思いますが、その場合は state も初期化されるので、state を使っても重複を防ぐことはできません。 おそらく答えをクリックしたら正解かどうか表示して次の問題に進むという処理を入れる予定だと思いますが、そのためには現在表示している問題を state で管理する必要があり、重複を解決する前にそちらを実装する方がいい気がします。
A.K

2020/12/29 03:43

回答有難うございます。 ご指摘の通り次の問題表示に関してはイベント処理のコードを使っていないです。 よってリロードしているのだと思います。 そして「答えをクリックしたら正解かどうか表示して次の問題に進むという処理」を入れたいのですが、stateで問題を管理する方法がわかりません。 以下のように考えてみましたが、これでは最初の問題が表示されるだけで次の問題が表示されませんでした。 間違いの部分があれば教えて頂けたら幸いです。 onClickQuiz = () => { for (let i = min; i < max; i++) { while (true) { let tmp = intRandom(min, max); if (!randomQuestions.includes(tmp)) { randomQuestions.push(tmp); randomQuestions.splice(tmp); setRandomQuestions(randomQuiz); break; } } } <Text style={styles.question} onPress={onClickQuiz}> {randomQuestions.questionText} </Text> <Text style={styles.answer} onPress={onClickQuiz}> {randomQuestions.answerOptions[0].answerText} </Text> <Text style={styles.answer} onPress={onClickQuiz}> {randomQuestions.answerOptions[1].answerText} </Text> <Text style={styles.answer} onPress={onClickQuiz}> {randomQuestions.answerOptions[2].answerText} </Text> <Text style={styles.answer} onPress={onClickQuiz}> {randomQuestions.answerOptions[3].answerText} </Text>
hoshi-takanori

2020/12/29 05:39

まず状態の定義が必要ですね。問題を表示して答えの入力を受け付ける状態と、入力された答えが正解かどうかを表示する状態は区別する必要があると思うので。
A.K

2020/12/29 09:13

度々アドバイス頂き有難うございます。 「入力された答えが正解かどうかを表示する状態」は以下のように書きました。 これで正解するとスコアに1加算され、表示もうまくできました。 const [score, setScore] = useState(0); const handleAnswerButtonClick = (isCorrect: boolean) => { if (isCorrect === true) { setScore(score + 1); } <TouchableOpacity onPress={() => { handleAnswerButtonClick(randomQuestions.answerOptions[0].isCorrect); }} > <Text style={styles.answer} > {randomQuestions.answerOptions[0].answerText} </Text> </TouchableOpacity>
A.K

2020/12/29 09:25

しかし「問題を表示して答えの入力を受け付ける状態」というのが色々試しましたが上手くいきません。 以前書いたコードのように、まずはクイズの問題の部分にonPressを追加しました。 そしてonPressのイベント処理の中に、重複させないためのコードを書きました。 function onClickQuiz() { const nextQuestion = currentQuestion + 1; if (nextQuestion < questions.length) { setCurrentQuestion(nextQuestion); } else { if (score + 1 === questions.length) { setScore(0); setCurrentQuestion(0); } else { setScore(0); setCurrentQuestion(0); } } } const randomQuiz: number[] = []; const min = 0; const max = questions.length; function intRandom(min: number, max: number) { return Math.floor(Math.random() * max); } for (let i = min; i < max; i++) { while (true) { let tmp = intRandom(min, max); if (!randomQuiz.includes(tmp)) { randomQuiz.push(tmp); randomQuiz.splice(tmp); break; } } } };; <Text style={styles.answer} onPress={()=>onClickQuiz()}> {randomQuestions.answerOptions[0].answerText} </Text>
A.K

2020/12/29 09:28

すると <Text style={styles.answer} onPress={()=>onClickQuiz()}> の onClickQuiz() の部分に、 「Cannot find name 'onClickQuiz'.ts(2304)」とエラーが出るようになりました。 上に同じ名前のonClickQuizがあるので、なぜこのエラーが出るのかわかりません。 そもそも onPress というイベント処理を text の中に入れることが間違っているのでしょうか? または function onClickQuiz() の中のコードの書き方が違うのでしょうか? 宜しくお願いいたします。
hoshi-takanori

2020/12/29 11:09

onClickQuiz のエラーについては、コメント欄だとインデントがなくなっちゃうのでよく分かりませんが、たぶん { 〜 } の対応関係がおかしくなってるんでしょうね。
A.K

2020/12/29 11:59

回答有難うございます。 そうなんですね。 stateを使ってもう少し試してみます。 空の配列にpushしてもリロードによって入った数字がまた空になり、前の数字が消えてしまい、その為のstateの準備が必要だということが分かり、とても助かりました。 stateの使い方を勉強したいと思います。 色々アドバイスを頂き有難うございました。
hoshi-takanori

2020/12/29 12:06

進展があったようで良かったです。回答欄に正解を書くこともできるのですが、自分で試行錯誤することでしか得られないことも多いと思ってるので、しばらく見守ってます。また何か疑問があったらこのコメント欄か、質問文を編集してくれれば見てみますよ。がんばってください。
A.K

2020/12/29 12:17

いつもご丁寧に教えていただき感謝しています。 はい、しばらくもがいてみます。 有難うございます! またお聞きしたときはアドバイス頂けたら幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問