Как предотвратить повторную инициализацию переменной при каждом рендеринге

#reactjs #state

Вопрос:

Предыстория: У меня есть приложение для викторины с карточками в react, где у меня есть переменная под названием «Вопросы», которая инициализируется массивом вопросов (которые являются объектами), для каждого из которых изначально установлено свойство длительности 15. Я хочу, чтобы это работало так, что каждый раз, когда пользователь отвечает на вопрос, свойство продолжительности изменяется в зависимости от того, правильно ли был дан ответ на вопрос или нет. И я всегда хочу отображать вопрос, который имеет наибольшую продолжительность.

Вопрос: Проблема в том, что я изменяю продолжительность, но затем она перерисовывается, и продолжительность возвращается к 15. Есть ли способ сохранить его глобальным, но при этом иметь возможность изменять свойства вопроса?

Я знаю, что этот код не является чистым, я просто хочу, чтобы общая структура была удалена.

 App.js
function App() {
    let questions =[
        {
            questionText: 'What is the capital of France?',
            answerOptions: [
                { answerText: 'New York', isCorrect: false },
                { answerText: 'London', isCorrect: false },
                { answerText: 'Paris', isCorrect: true },
                { answerText: 'Dublin', isCorrect: false },
            ],
        },
        {
            questionText: 'Who is CEO of Tesla?',
            answerOptions: [
                { answerText: 'Jeff Bezos', isCorrect: false },
                { answerText: 'Elon Musk', isCorrect: true },
                { answerText: 'Bill Gates', isCorrect: false },
                { answerText: 'Tony Stark', isCorrect: false },
            ]
        },
        {
            questionText: 'The iPhone was created by which company?',
            answerOptions: [
                { answerText: 'Apple', isCorrect: true },
                { answerText: 'Intel', isCorrect: false },
                { answerText: 'Amazon', isCorrect: false },
                { answerText: 'Microsoft', isCorrect: false },
            ],
        },
        {
            questionText: 'How many Harry Potter books are there?',
            answerOptions: [
                { answerText: '1', isCorrect: false },
                { answerText: '4', isCorrect: false },
                { answerText: '6', isCorrect: false },
                { answerText: '7', isCorrect: true },
            ],
        },
    ];
    const [quizTime, setQuizTime] = useState(90) // in seconds
    useEffect(() => {
        if (quizTime > 0) {
          setTimeout(() => setQuizTime(quizTime - 1), 1000);
          return () => clearTimeout(quizTime);
        } 
    });
    
    function checkAnswer(answer, question, time) {
        if (answer == null) {
            return;
        } else {
            const longerThanHalf = question.duration - time > question.duration / 2
            console.log(time)
            if (answer.isCorrect) {
                if (longerThanHalf) {
                    question.duration = question.duration - 2 >= 5 ? question.duration - 2 : 5
                } else {
                    question.duration = question.duration - 1 >= 5? question.duration - 1 : 5
                }
                
            } 
        }
        

    };

    const findMaxQuestion = () => {
        var max;
        questions.forEach( q => {
            if (q.duration !== undefined) {
                if (max !== undefined amp;amp; q.duration > max.duration) {
                    max = q
                } else max = q
            } else {
                q['duration'] = 15
                if (max !== undefined amp;amp; q.duration > max.duration) {
                    max = q
                } else max = q
            }
        })
        return max
    }
    if (quizTime > 0) {
        let maxQuestion = findMaxQuestion()
        console.log(maxQuestion)
        return (
            <div className="container">
                <div>{quizTime} seconds left</div>
                <FlashCard question = {maxQuestion} checkAnswer = {checkAnswer}/>
            </div>
        );
    }
    
}
 

Ответ №1:

Попробуй вот это. setInterval будет обновлять ваше состояние каждые 1000 мс. Замените свой эффект использования этим.

    useEffect(() => {
        if (quizTime > 0) {
          const time = setInterval(() => setQuizTime(quizTime - 1), 1000);
          return () => clearInterval(time);
        } 
    }, []);