首页 > 解决方案 > React js rendered value of state is one step behind

问题描述

I am new to react js. I have created a project through the create-react-app which is actually an "online test application". I am facing a problem in one module which is of the test screen which looks like this. In my jsx code, I am rendering value of state variables like this.

import React, { Component } from 'react';
import { Button, Radio, FormGroup } from 'react-bootstrap';
import Aux from '../../Auxilary/Auxilary';
import { Redirect } from 'react-router-dom';
 
import './TestScreen.css';

class TestScreen extends Component{
    
    state = {
        total_questions:60,
        current_question:1,
        time: 50,
        minutes: null,
        seconds: null
    };
    changeQuestion = () => {
        const question = this.state.current_question;
        this.setState({current_question: question+1});
    };
    componentDidMount(){
        const self = this;
        
        
       let timer = setInterval(function() {
            const newTime = self.state.time -1;
            const minute = Math.floor(self.state.time/60);
            const second = ("0" + self.state.time%60).slice(-2);
            self.setState({minutes: minute, seconds: second, time: newTime},() =>{
                console.log("Value of state Time: " + self.state.time);
            });
            
          
        }, 1000)
    }
   
    render(){
        
        return(
            <Aux>
                <div className="question-timer">
                    <div className="question-number">
                        <h3>Question {this.state.current_question}/{this.state.total_questions}</h3>
                    </div>
                    <div className="test-timer">
                        {this.state.time === 0 ?  <Redirect to='/' /> : console.log("Some Error Occured")}
                        <h3>{this.state.minutes}:{this.state.seconds}</h3>
                    </div>
                </div>
                <div className="test-window">
                    <div className="test-question-statement">
                        <h2><label>Test Question Statement</label></h2>
                    </div>
                    <div className="question-options">
                    
                    <FormGroup>
                        <Radio name="radioGroup">
                            Option 1
                        </Radio>{' '}
                        <Radio name="radioGroup">
                            Option 2
                        </Radio>{' '}
                        <Radio name="radioGroup">
                            Option 3
                        </Radio>
                    </FormGroup>
                    </div>
        {/****************************************Next Question Button************************************************/}
                    <div className="next-question-button-container">
                        <Button onClick={this.changeQuestion} bsClass="xavor-style">Next</Button>
                    </div>
        {/*********************************End of Next Question Button************************************************/}
                </div>
                
            </Aux>

        );
    }
}

export default TestScreen;

The problem I am facing is that the time rendered on the screen is one step behind the updated state. Since I am using a callback function to update the state, the value shown on the console is accurate but the rendered value in my JSX is one step behind. For example: if my console prints "state Time: 1" the value rendered will be 0:02. How can I update rendered value of state? Any help or suggestions will be appreciated. Thanks in advance.

标签: javascriptreactjs

解决方案


当时间达到 0 时,您在渲染时正在重定向。这就是您看不到 0:00 的原因。而不是直接重定向。在渲染后检查componentDidUpdate,如果time === 0,如果是清除间隔,并更新redirect状态的属性。重新渲染视图时,redirect: true状态将触发实际的重定向。

注意: React 的setState是异步的。当状态更新依赖于当前状态时,最好使用 updater 方法。

class TestScreen extends Component{

  state = {
      total_questions:60,
      current_question:1,
      time: 50,
      minutes: null,
      seconds: null,
      redirect: false,
  };

  changeQuestion = () =>
    this.setState((prevState) => ({
      current_question: prevState.current_question + 1
    }));

  componentDidMount() {
    // assign the timer to this.timer, so you can clear it in componentWillUnmount
    this.timer = setInterval(() =>
      this.setState(({ time }) => ({
        minutes: time / 60,
        seconds: ("0" + time % 60).slice(-2),
        time: time - 1
      }))
    , 1000)
  }

  componentDidUpdate() {
    const { time, redirect } = this.state;

    if(!reidrect && time === 0 && ) {
      clearInterval(this.timer);

      this.setState({
        redirect: true
      });
    }
  }

  render() {
    const { time, redirect, minutes, seconds } = this.state;

    // just the relevant JSX parts
    return (
      <div className="test-timer">
        {redirect ?  <Redirect to='/' /> : console.log("Some Error Occured")}
        <h3>{minutes}:{seconds}</h3>
      </div>
    );
  }
}

推荐阅读