计时器倒数至0时如何触发事件 在父组件中:在计时器组件中:在测验组件中:在计时器组件中

如何解决计时器倒数至0时如何触发事件 在父组件中:在计时器组件中:在测验组件中:在计时器组件中

我有一个父组件,其中有计时器组件。计时器从15分钟开始计时,直到0为止。当我的计时器显示为0时,我想触发一个提交按钮事件,则提交按钮位于Quiz组件内部(Quiz组件也是Parent组件的子组件)。我发现p标签更改时可以使用MutationObserver。我不确定这是正确且唯一的方法,还是有更好的方法来实现这一目标。

父组件:

import React,{ Component } from 'react';
import '../css/App.css'
import Quiz from './Quiz';
import Timer from './Timer';
import { connect } from 'react-redux';
import { ActionTypes } from '../redux/constants/actionTypes';
import { saveQuizAll,getQuizIndex } from '../commonjs/common.js';

const mapStateToProps = state => { return { ...state.quiz,...state.quizAll } };

const mapDispatchToProps = dispatch => ({
  onQuizLoad: payload => dispatch({ type: ActionTypes.QuizLoad,payload }),onQuizChange: payload => dispatch({ type: ActionTypes.QuizAnswerAll,onPagerUpdate: payload => dispatch({ type: ActionTypes.PagerUpdate,payload })
});

class QuizContainer extends Component {
  state = {
    quizes: [
      { id: 'data/class1.json',name: 'Class 1' },{ id: 'data/class2.json',name: 'Class 2' },{ id: 'data/class3.json',name: 'Class 3' },{ id: 'data/class4.json',name: 'Class 4' },],quizId: 'data/class1.json'
  };

  pager = {
    index: 0,size: 1,count: 1
  }

  componentDidMount() {
    console.log('componentDidMount');
    this.load(this.state.quizId);
  }

  load(quizId,isValReload) {
    console.log('In load');
    let url = quizId || this.props.quizId;
    if (isValReload) {
      let quiz = this.props.quizAll.find(a => url.indexOf(`${a.id}.`) !== -1);
      console.log('In load quiz : ',quiz);
      this.pager.count = quiz.questions.length / this.pager.size;
      this.props.onQuizLoad(quiz);
      this.props.onPagerUpdate(this.pager);
    }
    else {
      fetch(`../${url}`).then(res => res.json()).then(res => {
        let quiz = res;
        quiz.questions.forEach(q => {
          q.options.forEach(o => o.selected = false);
        });
        quiz.config = Object.assign(this.props.quiz.config || {},quiz.config);
        this.pager.count = quiz.questions.length / this.pager.size;
        this.props.onQuizLoad(quiz);
        this.props.onPagerUpdate(this.pager);
      });
    }
  }

  //This event implements restriction to change class without finishing curretnly selectd class
  onClassClick = (e) => {
    let qus = this.props.quiz.questions;
    // console.log(qus);
    let isNotAllAns = qus.some((q,i) => {
      var isNot = false;
      if (q.answerType.id !== 3 && q.answerType.id !== 4) {
        isNot = (q.options.find((o) => o.selected === true)) === undefined;
      }
      else {
        // console.log('q',q);
        isNot = ((q.answers === "" || q.answers.length === 0));
      }
      return isNot;
    });
    if (isNotAllAns) {
      alert('Please complete the quiz.');
      e.stopPropagation();
    }
  }

  /*
  saveQuizAll(_quizAll,_quiz) {
    let allQuiz = [];
    //,_quizAll,_quiz;
    // if (true) {
    //   _quiz = this.quiz;
    //   _quizAll = this.quizAll;
    // }

    console.log(this,_quiz,_quizAll);
    if (_quiz.questions.length !== 0) {

      if (_quizAll.length !== undefined) {
        console.log('Not Initial Setup Splice',_quiz.id);
        allQuiz = _quizAll;
        const qIndex = this.getQuizIndex(_quiz.id.toString());
        if (qIndex > -1) {
          allQuiz.splice(qIndex,1,_quiz);
        }
        else {
          allQuiz.splice(_quizAll.length,_quiz);
          // allQuiz.splice(this.props.quizAll.length-1,this.props.quizAll,this.props.quiz);
        }
      }
      else {
        allQuiz[0] = _quiz;
      }
      return allQuiz;
      // if (true) {
      //   this.onQuizChange(allQuiz);
      // }
    }
  }
  */

  onChange = (e) => {
    // console.log(this.props.quizAll,this.props.quizAll.length);
    let allQuiz = [];
    allQuiz = saveQuizAll(this.props.quizAll,this.props.quiz);

    //below code converted into saveQuizAll funstion
    /*
    if (this.props.quizAll.length !== undefined) {
      console.log('Not Initial Setup Splice',this.props.quiz.id);
      allQuiz = this.props.quizAll;
      const qIndex = this.getQuizIndex(this.props.quiz.id.toString());
      if (qIndex > -1) {
        allQuiz.splice(qIndex,this.props.quiz);
      }
      else {
        allQuiz.splice(this.props.quizAll.length,this.props.quiz);
        // allQuiz.splice(this.props.quizAll.length-1,this.props.quiz);
      }
    }
    else {
      allQuiz[0] = this.props.quiz;
    }
    */

    // console.log('allQuiz Out - ',allQuiz);
    this.props.onQuizChange(allQuiz);
    console.log('Check QuizAll - ',this.props.quizAll);
    const aQuiz = JSON.parse(JSON.stringify(this.props.quizAll));
    this.setState({ quizId: e.target.value });
    if (aQuiz.length !== undefined && getQuizIndex(this.props.quizAll,e.target.value) > -1) {
      // console.log(aQuiz.findIndex(a => e.target.value.indexOf(`${a.id}.`) !== -1));
      this.load(e.target.value,true);
    }
    else {
      this.setState({ quizId: e.target.value });
      this.load(e.target.value,false);
    }
  }

  // getQuizIndex(qID) {
  //   return this.props.quizAll.findIndex(a => (qID.indexOf(`${a.id}.`) !== -1 || qID.indexOf(`${a.id}`) !== -1));
  // }

  render() {
    return (
      <div className="container">
        <header className="p-2">
          <div className="row">
            <div className="col-6">
              <h3>DADt Application</h3>

            </div>
            <div className="col-6 text-right">
              <label className="mr-1">Select Quiz:</label>
              <select onChange={this.onChange} onClick={this.onClassClick}>
                {this.state.quizes.map(q => <option key={q.id} value={q.id}>{q.name}</option>)}
              </select>
            </div>
          </div>
        </header>
        <Timer duration={900}/>
        <Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} />
      </div>
    );
  }
}

export default connect(mapStateToProps,mapDispatchToProps)(QuizContainer);

这是我的计时器组件

    import React,{ Component } from 'react'

class Timer extends Component {
    constructor(props) {
        super(props);
        this.state = {
            seconds: 0
        };
    }

    tick() {
        this.setState((prevState) => ({
            seconds: prevState.seconds + 1
        }));
    }

    componentDidMount() {
        this.interval = setInterval(() => this.tick(),1000);
    }

    componentWillUnmount() {
        clearInterval(this.interval);
    }

    render() {
        const { duration } = this.props;
        let timeLeft = duration - this.state.seconds;
        timeLeft = Number(timeLeft);
        let minutes = Math.floor(timeLeft % 3600 / 60);
        let seconds = Math.floor(timeLeft % 3600 % 60);

        let minutesDisplay = minutes > 0 ? minutes + (minutes === 1 ? " : " : " : ") : "";
        let secondsDisplay = seconds > 0 ? seconds + (seconds === 1 ? "" : "") : "";

    return <p className="badge badge-success">Time Left: {minutesDisplay}{secondsDisplay}</p>;
    }
}

export default Timer;

测验组件:

import React,{ Component } from 'react';
import { ActionTypes } from '../redux/constants/actionTypes';
import Review from './Review';
import Questions from './Questions';
import Result from './Result';
import { connect } from 'react-redux';
// import { saveQuizAll } from '../commonjs/common.js';


const mapStateToProps = state => { return { ...state.quiz,...state.mode,...state.pager,...state.quizAll } };

const mapDispatchToProps = dispatch => ({
    onSubmit: payload => dispatch({ type: ActionTypes.QuizSubmit,payload })
});

class Quiz extends Component {
    move = (e) => {
        let id = e.target.id;
        let index = 0;
        if (id === 'first')
            index = 0;
        else if (id === 'prev')
            index = this.props.pager.index - 1;
        else if (id === 'next') {
            index = this.props.pager.index + 1;
          }
        else if (id === 'last')
            index = this.props.pager.count - 1;
        else
            index = parseInt(e.target.id,10);

        if (index >= 0 && index < this.props.pager.count) {
            let pager = {
                index: index,count: this.props.pager.count
            };
            this.props.onPagerUpdate(pager);
        }
    }

    saveStore(e) {
      let allQuiz = [];
      console.log(this,e);
      allQuiz = this.props.saveAll(e.props.quizAll,e.props.quiz);
      console.log(allQuiz);
      this.props.onQuizChange(allQuiz);
    }

    setMode = (e) => this.props.onSubmit(e.target.id);

    // setMode(e) {
    //   console.log('in mode',e);this.props.onSubmit(e.target.id);
    // }

    renderMode() {
      console.log('Inside here',this.props.mode);
        if (this.props.mode === 'quiz') {
            return (<Questions move={this.move} />)
        } else if (this.props.mode === 'review') {
            return (<Review quiz={this.props.quiz} move={this.move} />)
        } else {
            console.log('Before Results');
            const divSel = document.querySelector('div.col-6.text-right');
            // console.log('divSel',divSel);
            if (divSel) {
              divSel.style.display = "none";
            }
            return (<Result questions={this.props.quizAll || []} />)
        }
    }

    render() {
        return (
            <div>
                {this.renderMode()}
                {(this.props.mode !== 'submit') &&
                    <div>
                        <hr />
                        <button id="quiz" className="btn btn-primary" onClick={this.setMode}>Quiz</button>
                        <button id="review" className="btn btn-primary" onClick={this.setMode}>Review</button>
                        <button id="submit" className="btn btn-primary" onClick={(e) => {this.setMode(e); this.saveStore(this)}}>Submit Quiz</button >
                    </div >}
            </div>
        )
    }
}

export default connect(mapStateToProps,mapDispatchToProps)(Quiz);

解决方法

在Timer组件中提供prop方法onTimeFinished。然后,您可以在渲染功能中添加

{ !(this.props.duration-this.state.seconds) && this.props.onTimeFinished() }

参考:React Conditional Rendering

,

尝试一下:

父项:

// state
state = {
    triggerSubmit: false
}  

// functions
doSubmit = () => {
    this.setState({ triggerSubmit: true });
}
resetSubmit = () => {
    this.setState({ triggerSubmit: false });
}  

// jsx
<Timer duration={900} doSubmit={this.doSubmit} />
<Quiz 
    quiz={this.state.quiz}
    quizId={this.state.quizId}
    saveAll={saveQuizAll}
    mode={this.state.mode}
    resetSubmit={this.resetSubmit}
    triggerSubmit={this.state.triggerSubmit} />

计时器组件:

// function
doSubmit = (timeLeft) => {
  if (timeLeft === 0) {
    this.props.doSubmit();
  }
}  

// jsx
<p className="badge badge-success"
   onChange={() => {this.doSubmit(timeLeft)}>
   Time Left: {minutesDisplay}{secondsDisplay}
</p>

测验组件:

// state
state = {
    triggerSubmit: this.props.triggerSubmit
}  

// function
triggerSubmit = () => {
    if (this.state.triggerSubmit) {
       your trigger submit code here...
       this.props.resetSubmit();
    }
}
,

我认为您可以采用两种方法。

1。 “反应”方式

在父组件中:

// ...
constructor(props) {
  // ...
  this.state = {
    timeExpired: false
  };
}
    
const onTimeExpired = () => {
  this.setState({timeExpired: true});
}
   
// ...
    
render() {
  return (
    <div className="container">
      { // ... }
      <Timer duration={900} onTimeExpired={onTimeExpired}/>
      <Quiz quiz={this.state.quiz} quizId={this.state.quizId} saveAll={saveQuizAll} mode={this.state.mode} triggerSubmit={this.state.timeExpired} />
      </div>
    );
}

在计时器组件中:

// ...

componentDidUpdate() {
  if (this.state.seconds === this.props.duration) {
    this.props.onTimeExpired();
  }
}

// ...

在测验组件中:

// ...

componentDidUpdate() {
  if (this.props.triggerSubmit) {
    // Do whatever you do on submit
  }
}

// ...

2。 “快速而肮脏”的方式:

在计时器组件中

// ...

componentDidUpdate() {
  if (this.state.seconds === this.props.duration) {
    const quizForm = document.getElementById('quizFormId');
    quizForm && quizForm.submit();
  }
}

// ...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-