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

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

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

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

1回答

327閲覧

usestateで非同期でsetされる変数を読み取れない場合の対処方法を知りたい。

hashikunmaru

総合スコア6

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2022/07/22 07:24

編集2022/07/22 09:43

前提

react×TSでクイズアプリを作っています。
ランダムでクイズを選択肢、それをクイズリストに追加していきたいのですが、上手く追加できずに困っています。

実現したいこと

  • setQuizeez();後のsetQuestion()の際に、quizListの値が参照できるようにしたい。

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

setQuizeez()によって、quizListにクイズが追加されたのち、setQuestion()が実行できるとよいのですが、setQuizList()が非同期で走ってしまうため、上手くQuizListの値が参照できません。
このような場合、どのような対処方法が良いのでしょうか。

該当のソースコード

ts

1import React, { ChangeEvent, useEffect, useState } from "react"; 2import { quizzes, Quiz } from "../data/quizzes"; 3 4export type GameSceneProps = { 5 setScene: (scene: string) => void; 6}; 7 8export const GameScene: React.FC<GameSceneProps> = ({ setScene }) => { 9 const [quizProgress, setQuizProgress] = useState<number>(1); 10 const [inputAnswer, setInputAnswer] = useState<string>(""); 11 const [inputCheck, setinputCheck] = useState<string>(""); 12 const [question, setQuestion] = useState<string>(""); 13 const [answer, setAnswer] = useState<string>(""); 14 const questinoNum = 3; 15 const [quizList, setQuizList] = useState<Quiz[]>([]); 16 17 const randomNumber = (max: number) => { 18 return Math.floor(Math.random() * max); 19 }; 20 21 const setQuizeez = () => { 22 const max = quizzes.length; 23 console.log(quizList); 24 for (let i = 0; i < questinoNum; i++) { 25 console.log(quizzes[randomNumber(max)]); 26 setQuizList([...quizList, quizzes[randomNumber(max)]]); 27 } 28 console.log(quizList); 29 }; 30 31 const onchangeText = (e: ChangeEvent<HTMLInputElement>) => { 32 setInputAnswer(e.target.value); 33 }; 34 35 const submitAnswer = () => { 36 console.log(inputAnswer); 37 console.log(answer); 38 if (inputAnswer == answer) { 39 setQuizProgress((count) => count + 1); 40 setinputCheck(""); 41 console.log(quizProgress); 42 console.log(quizList); 43 setQuestion(quizList[quizProgress - 1]["question"]); 44 setAnswer(quizList[quizProgress - 1]["answer"]); 45 } else { 46 setinputCheck("違うよ!"); 47 } 48 setInputAnswer(""); 49 }; 50 51 useEffect(() => { 52 console.log(quizList); 53 setQuizeez(); 54 setQuestion(quizList[quizProgress - 1]["question"]); 55 setAnswer(quizList[quizProgress - 1]["answer"]); 56 }, []); 57 58 useEffect(() => { 59 if (quizProgress === 4) { 60 setScene("result"); 61 } 62 }, [quizProgress]);

試したこと

以下のように、quizListが更新された際に、setQuestion()が動作するように変更した。
しかし、そもそもsetQuizeez()の中で、quizListが更新されない状態で、for文が回っているのでquestionNum=3の場合は3回目のquizzes[randomNumber(max)]がsetQuizListに収納された状態になってしまう。(本来はクイズが3問収納されて欲しい)

ts

1 const setQuizeez = () => { 2 const max = quizzes.length; 3 for (let i = 0; i < questinoNum; i++) { 4 console.log(quizzes[randomNumber(max)]); 5 setQuizList([...quizList, quizzes[randomNumber(max)]]); 6 } 7 }; 8 9 useEffect(() => { 10 console.log(quizList); 11 setQuizeez(); 12 }, []); 13 14 useEffect(() => { 15 if (quizList.length !== 0) { 16 setQuestion(quizList[quizProgress - 1]["question"]); 17 setAnswer(quizList[quizProgress - 1]["answer"]); 18 } 19 }, [quizList]); 20 21

追記①

以下のコードで実行したところ、setQuizeez()が2回実行され、配列に6つの要素が格納されてしまします。
setQuizeezは1度しか動かない認識ですが、なぜこのようなことが起こるのでしょうか?(開発環境のみuseeffectが2回動くようになっているみたいなのを見かけましたが、それが原因でしょうか?)

また、2回動くのはまだ分かるのですが、以下のコードにし、consoleを確認すると、ランダムで選出されたクイズ6つと、配列に格納されているクイズ6つが一致していないのですが、これはなぜでしょうか?
イメージ説明

ts

1 const setQuizeez = () => { 2 const max = quizzes.length; 3 for (let i = 0; i < questinoNum; i++) { 4 var _q = quizzes[randomNumber(max)]; 5 console.log(_q); 6 setQuizList((quizList) => [...quizList, _q]); 7 // setQuizList((quizList) => [...quizList, quizzes[randomNumber(max)]]); 8 } 9 }; 10

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

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

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

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

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

hoshi-takanori

2022/07/22 08:22

for 文の中で毎回 setQuizList するのが間違い。ローカル変数で配列を作ってそこに 3 つ追加して、最後に一回だけ setQuizList すると良いでしょう。
hashikunmaru

2022/07/22 09:54

ありがとうございます。 最後にまとめてsetするのが良いのですね!
maisumakun

2022/07/23 14:41

> ランダムで選出されたクイズ6つと、配列に格納されているクイズ6つが一致していないのですが どれが抽出されたかは一致しています。
guest

回答1

0

そもそもsetQuizeez()の中で、quizListが更新されない状態で、for文が回っているので

もとの値を使って書き換える場合、古い値を引数にとって新しい値を返す関数setに渡してください。

javascript

1setQuizList(oldList => [...oldList, quizzes[randomNumber(max)]]);

投稿2022/07/22 08:29

maisumakun

総合スコア145192

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

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

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

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問