skip to Main Content

In my code (React Native) to avoid the "Too many re-renders" error I used a useEffect hook. I would expect the useEffect to run when the component PracticeTest first runs but it doesn’t. The problem with hte code isn’t that the useEffect runs during every render, but rather it doesn’t run at all. Can someone explain how I can fix it?

function PracticeTest({setCurrentMode}){
  const [index, setIndex] = useState(0);

  const [selected, setSelected] = useState(0);
  const [feedback, setFeedback] = useState('');
  const [score, setScore] = useState(0);
  
  // Create 'isCorrect' var to designate if ready to move on to the next question
  const [isCorrect, setIsCorrect] = useState(false);

  // get only the questions needed
  testQuestions = require('./testQuestions.json');
  let questionAnswers = [];

  let firstQuestionIndex;
  let lastQuestionIndex;
  let testLength = lastQuestionIndex - firstQuestionIndex;
  const [shuffled, setShuffled] = useState(false);

  const [done, setDone] = useState(false);



  
  
  useEffect(() => {
    questionAnswers = [];


    for(var i=0; i<testQuestions.length; i++){
      if((i>=firstQuestionIndex) && (i< lastQuestionIndex)){
        questionAnswers.push(testQuestions[i]);
        
      }
    }
      
      
      
    shuffle(questionAnswers);
      
    testLength = 10;
    shuffled = true;
    
  });
    

  // if quizType is "practiceTest" then the questions will be randomly selected and jumbled
  // Source for shuffle function (modified by me): https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
  function shuffle(array) {
    if(shuffled){
      console.log("ALREADY SHUFFLEDDDDDDDDDDDDDD");
    }
    else{
      
      let currentIndex = array.length;
    
      // While there remain elements to shuffle...
      while (currentIndex != 0) {
    
        // Pick a remaining element...
        let randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex--;
   
        // And swap it with the current element.
        [array[currentIndex], array[randomIndex]] = [
          array[randomIndex], array[currentIndex]];
      }
      console.log("Shuffle!!");
    }
  }
  
  

  let question = questionAnswers[index].question;


  function check(){
    if(selected == questionAnswers[index].correctID){
      // add 1 point to score if the feedback is blank
      if(feedback==''){
        setScore(score+1);
      }
      setFeedback('Correct!');
      setIsCorrect(true);
    }
    else{
      setFeedback("Try again");
    }
  }

  function proceed() {
    if((index + 1) >= testLength){
      // Code to be executed if done
      setDone(true);
    }
    else{
      setIndex(index + 1);
      setIsCorrect(false);
      setColor1('#FF6868');
      setColor2('#FF6868');
      setColor3('#FF6868');
      setColor4('#FF6868');
      setFeedback('');
    }
    
    
    
  }

  const [color1, setColor1] = useState('#FF6868');
  const [color2, setColor2] = useState('#FF6868');
  const [color3, setColor3] = useState('#FF6868');
  const [color4, setColor4] = useState('#FF6868');

  return (
    <View>
      {done ? 
        <QuizDone setCurrentMode={setCurrentMode} score={score} testLength={testLength}/>
      : 
        <View style={styles.app}>
          <Text style={styles.logo}>Testing your Knowledge</Text>
          <Text style={styles.question}>{question}</Text>
          <AnswerChoices setSelected={setSelected} index={index} questionAnswers={questionAnswers} color1={color1} color2={color2} color3={color3} color4={color4} setColor1={setColor1} setColor2={setColor2} setColor3={setColor3} setColor4={setColor4} />
          <BackButton setCurrentMode={setCurrentMode}></BackButton>
          {/** Feedback */}
          <View style={{
            position: 'absolute',
            width: 144,
            height: 42,
            top: 595,
            left: 63,
            justifyContent: 'center',
          }}>
            <Text>{feedback}</Text>
          </View>
          {/** Check Answer */}
          {
            isCorrect ? 
          <TouchableOpacity style={styles.checkButton} onPress={proceed}>
            <Text style={{color: 'white', alignSelf: 'center',}}>Move on</Text>
          </TouchableOpacity>
          :
          <TouchableOpacity style={styles.checkButton} onPress={check}>
            <Text style={{color: 'white', alignSelf: 'center',}}>Check</Text>
          </TouchableOpacity>
          }
        </View>
        }
    </View>
  )
}

I tried may things, like adding a console.log to see if the useEffect was even running, which it didn’t. And because the code inside of the useEffect isn’t running, the array "questionAnswers" has no value.

2

Answers


  1. If You don’t use a dependency array, the useEffect will run on every render and is useless. If you only need the effect to run on initial render, you can use an empty array as a dependency array: useEffect(() => {...}, [])

    Login or Signup to reply.
  2. I think there is an issue with how you are setting the variables and also the dependency array is missing, set dependency array to [] if you want it to run only once -> on mount

    Set variable like this:

    const [index, setIndex] = useState(0);
      const [selected, setSelected] = useState(0);
      const [feedback, setFeedback] = useState('');
      const [score, setScore] = useState(0);
      const [isCorrect, setIsCorrect] = useState(false);
      const [done, setDone] = useState(false);
      const [color1, setColor1] = useState('#FF6868');
      const [color2, setColor2] = useState('#FF6868');
      const [color3, setColor3] = useState('#FF6868');
      const [color4, setColor4] = useState('#FF6868');
      const [questionAnswers, setQuestionAnswers] = useState([]);
      const [shuffled, setShuffled] = useState(false);
      const firstQuestionIndex = 0; // Set the appropriate index
      const lastQuestionIndex = 10; // Set the appropriate index
      const testLength = lastQuestionIndex - firstQuestionIndex;
    
      const testQuestions = require('./testQuestions.json');
    
      useEffect(() => {
        let questionsToShuffle = [];
        for (let i = 0; i < testQuestions.length; i++) {
          if (i >= firstQuestionIndex && i < lastQuestionIndex) {
            questionsToShuffle.push(testQuestions[i]);
          }
        }
    
        shuffle(questionsToShuffle);
        setQuestionAnswers(questionsToShuffle);
        setShuffled(true);
      }, []); // Empty dependencies array ensures this runs only once
    
      function shuffle(array) {
        if (shuffled) {
          console.log("ALREADY SHUFFLEDDDDDDDDDDDDDD");
        } else {
          let currentIndex = array.length;
          while (currentIndex !== 0) {
            let randomIndex = Math.floor(Math.random() * currentIndex);
            currentIndex--;
            [array[currentIndex], array[randomIndex]] = [array[randomIndex], array[currentIndex]];
          }
          console.log("Shuffle!!");
        }
      }
    
      const question = questionAnswers.length > 0 ? questionAnswers[index].question : '';
    
      function check() {
        if (selected === questionAnswers[index].correctID) {
          if (feedback === '') {
            setScore(score + 1);
          }
          setFeedback('Correct!');
          setIsCorrect(true);
        } else {
          setFeedback("Try again");
        }
      }
    
      function proceed() {
        if ((index + 1) >= testLength) {
          setDone(true);
        } else {
          setIndex(index + 1);
          setIsCorrect(false);
          setColor1('#FF6868');
          setColor2('#FF6868');
          setColor3('#FF6868');
          setColor4('#FF6868');
          setFeedback('');
        }
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search