I'm building this simple quiz app in React where a random Korean hangul from a 40-item Data.json
is displayed on the screen and users have 5 buttons with different answers which also come from Data.json
.
For clarification, this is my application and the components I'm using. All components are siblings and live inside App.js
.
What the application is suppose to do is to create a 5-item random array and select one of these as the right answer before render. If the user taps the right button all the components should be re-rendered with different items. That's why I decided to use the useEffect()
hook.
But what is currently happening is:
- Every
console.log
is being displayed twice in the console. The first time variables are empty and in the second time they display the values they should have; - The randomOptions array has 10 items instead of 5;
- If the
<Question/>
component is in the code then I get errors andconsole.log
tells me the values from myuseState
hooks are undefined. If<Question/>
is removed I get the console shown in the picture below.
Console for clarification:
App.js
component:
import './App.css';
import Data from './data/data.json';
import Header from './components/Header';
import Question from './components/Question';
import { useState, useEffect } from 'react';
function App() {
const [index, setIndex] = useState(Math.floor(Math.random() * 5)); // Tells us what the index of the right answer is
const [randomOptions, setRandomOptions] = useState([]); // Random array with 5 items from Data.json that are the options
const [question, setQuestion] = useState([]); // The question that goes to <Question/> and people need to guess
const randomizeButtonAnswer = () => {
let previousArray = randomOptions;
setRandomOptions([]);
for (let i=0; i < 5; i ){
let randomNumber = Math.floor(Math.random() * Data.length);
if (!randomOptions.includes(randomNumber) && !previousArray.includes(randomNumber)) {
setRandomOptions(randomOptions.push(randomNumber));
} else {
i--;
}
}
setRandomOptions(randomOptions.sort(() => Math.random() - 0.5));
setQuestion(randomOptions[index]);
}
useEffect(() => {
randomizeButtonAnswer();
}, [index])
console.log('index is ' index); // 3
console.log('randomOptions is ' randomOptions); // 33,9,3,26,8,20,0,12,29,25
console.log('question is ' question); //26
return (
<div className="App">
<Header />
<Question answer={question}/>
</div>
);
}
export default App;
Question.js
component
import './Question.css';
import Data from '../data/data.json';
const Question = ({ answer }) => {
return (
<div className="question-wrapper">
<h1 className="question"><span className="highlight">{Data[answer].character}</span></h1>
<span>{Data[answer].character} = {Data[answer].char_id} </span>
</div>
);
}
export default Question;
I'm completely lost here. Not sure why things are being rendered twice or why when present <Question/>
makes my variables become undefined. I assume something inside randomizeButtonAnswer
is broken but I've been unable to find what exactly.
Small disclaimer: I'm a complete noob to React so if I'm doing something that is wrong or a bad practice do let me know.
Thanks for your time!
CodePudding user response:
I tried to fix your code but it's complicated and wrong at many points so I decided to write the function myself. Sorry about that.
there are many problem with your code.
- About log 2 times. It is
<StrictMode />
- You should understand more about React State. It not change right in the place you write it, it's queue up and update when your functions end. set 1 state 2 time in 1 function does not mean anything.
- Don't do
i--
in for loop like that which is complicated to understand how things goes and hard to debug. use while loop or for best justdon't
. check the condition and log out or have some handle for it. - Wanna log? log inside React Component? use
useEffect
. - Default state of Question is not [].
- Always do conditional render if default value of state is possible be either
null
orundefined
.
Good luck with your React journey.