javascript - 在 React.js 中交换元素并获取 <error>

标签 javascript backbone.js reactjs

所以我有一副学习卡,并且有一个在顶部开始学习类(class)的链接。用户完成学习 session 后,我不希望用户在两分钟内访问学习 session 链接。我没有使用链接,而是使用 timeLeft 状态从 2 分钟倒数到 0 的计时器。 2 分钟后,计时器消失,并通过在 componentDidUpdate 中将状态设置为“链接”来替换为学习 session 的链接。一切都按预期工作,除了 react 会减慢甲板页面的渲染速度。我的代码如下:

/** @jsx React.DOM */
var cardModel = require("../models/card.js");
var Card = React.createFactory(require("./card.jsx"));
//var BackboneMixin = require("../../BackboneMixin.js");

var DeckShow = React.createClass({
  //mixins: [BackboneMixin],
  getInitialState: function() {
    return {elapsedTime: this.setTime(), timeLeft: 0, cards: this.props.cards, cardsCollection: [], cardShow: "question", empty: "none" }
  },

  componentDidMount: function () {
    this.props.cardCollection.fetch();
    var boxes = this.getBoxState(this.props.deck)
    this.setState({timeLeft: this.props.delay - this.state.elapsedTime})
    this.interval = setInterval(this.countDown, 1000)
    var startBox = [];
    var i = 0;
    while (i <= (this.props.deck.get("session_num") % 5)) {
      startBox.concat(boxes[i])
      i += 1;
    }

    if ((this.props.deck.get("cards").length > 0) && (this.state.elapsedTime >= this.props.delay || this.props.deck.get("last_session") === null)) {
      this.setState({empty: "link"});
    } else if (this.props.deck.get("cards").length > 0 && startBox.length === 0) {
      this.setState({empty: "timer"})
      //setTimeout(this.setState({empty: "link"}), this.state.timeLeft)
    }
    else{
      this.setState({empty: "none"});
    }
  },

  componentDidUpdate: function(nextProps, nextState) {
    this.props.deck.on("sync", function(){
      this.forceUpdate();
    }, this)

    if (this.state.timeLeft <= 0) {
      clearInterval(this.interval)
      this.setState({empty: "link"})
      this.forceUpdate();
    }
  },

  componentWillUpdate: function(){
  //      var that = this;
  //      if (this.state.elapsedTime <= 0) {
  //          that.setState({empty: that.link})
  //      }
  },

  componentWillUnmount: function(){
    clearInterval(this.interval);
  },

  setTime: function(){
    var last = this.props.deck.get("last_session") || Date.now();
    return Date.now() - last;
  },

  getBoxState: function(deck) {
    var boxState = [[],[],[],[],[]]
    var deckCards = deck.get("cards");
    for (var i = 0; i < deckCards.length; i++) {
      boxState[deckCards[i].box_id].push(deckCards[i])
    }

    return boxState;
  },

  countDown: function() {
    this.setState({timeLeft: this.state.timeLeft - 1000})
  },

  handleSubmit: function(event) {
    event.preventDefault();
    var question = this.refs.question.getDOMNode().value.trim();
    var answer = this.refs.answer.getDOMNode().value.trim();
    if ((!question) || (!answer)) {
      return;
    } 

    this.refs.question.getDOMNode().value = '';
    this.refs.answer.getDOMNode().value = '';
    var cards = this.props.cardCollection.models[0].get("objects")

    var newCard = {
      question: question,
      answer: answer,
      deck_id: this.props.id,
      box_id: 0
    }

    this.props.cardCollection.create(newCard, {wait: true})
    var cardArr = this.state.cards
    cardArr.push(newCard)
    this.setState({empty: "link"});
    this.setState({cards: cardArr})
    return;
  },

  render: function() {
    var header = "Deck: " + this.props.deck.get("name");

    var cardsList = this.props.cards.map(function(card) {
      return <Card box={card.box_id}
            key={card.id}
            cardQuestion={card.question}
            cardAnswer={card.answer}
            text={card.answer} />
    });

    var view;
    var empty = this.state.empty;
    var that = this;

    var elapsed = this.state.timeLeft;
    var none = <p>{"There are no cards"}</p>
    var timer = <p>{"Time till next: " + Math.floor(elapsed/60000) + ":" + Math.floor((elapsed % 60000)/1000)}</p>
    var link = <a href={"#/decks/" + this.props.id + "/study"}>{"Study Mode"}</a>

    if (this.state.empty === "link") {
      view = link;
    } else if (this.state.empty === "timer") {
      view = timer;
    } else {
      view = none;
    }

    return (
      <div className="cardList">
        <h2>{header}</h2>
        <div id="study-mode">
          {view}
        </div>
        <ul id="deck-index">{cardsList}</ul>
        <div className="input">
          <form onSubmit={this.handleSubmit} className="form-horizontal">
            <div className="form-group">
              <input
                type="text"
                ref="question"
                placeholder="Add a new question" />
              <br />
              <input
                type="textarea"
                ref="answer"
                placeholder="Add an answer" />
              <br />
              <input type="submit" value="Add Card" />
            </div>
          </form>
        </div>
      </div>
    );
  }
});

module.exports = DeckShow;

错误跟踪如下:

ReactElement @ react.js:9890ReactElement.createElement @ react.js:9972ReactClass.createClass.render @ react.js:8288ReactCompositeComponentMixin._renderValidatedComponentWithoutOwnerOrContext @ react.js:6925ReactCompositeComponentMixin._renderValidatedComponent @ react.js:6951ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6882ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.receiveComponent @ react.js:6647ReactReconciler.receiveComponent @ react.js:14131ReactChildReconciler.updateChildren @ react.js:4779ReactMultiChild.Mixin._updateChildren @ react.js:12900ReactMultiChild.Mixin.updateChildren @ react.js:12874ReactDOMComponent.Mixin._updateDOMChildren @ react.js:7862ReactDOMComponent.Mixin.updateComponent @ react.js:7713ReactDOMComponent.Mixin.receiveComponent @ react.js:7697ReactReconciler.receiveComponent @ react.js:14131ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6884ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.receiveComponent @ react.js:6647ReactReconciler.receiveComponent @ react.js:14131ReactChildReconciler.updateChildren @ react.js:4779ReactMultiChild.Mixin._updateChildren @ react.js:12900ReactMultiChild.Mixin.updateChildren @ react.js:12874ReactDOMComponent.Mixin._updateDOMChildren @ react.js:7862ReactDOMComponent.Mixin.updateComponent @ react.js:7713ReactDOMComponent.Mixin.receiveComponent @ react.js:7697ReactReconciler.receiveComponent @ react.js:14131ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6884ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.receiveComponent @ react.js:6647ReactReconciler.receiveComponent @ react.js:14131ReactChildReconciler.updateChildren @ react.js:4779ReactMultiChild.Mixin._updateChildren @ react.js:12900ReactMultiChild.Mixin.updateChildren @ react.js:12874ReactDOMComponent.Mixin._updateDOMChildren @ react.js:7862ReactDOMComponent.Mixin.updateComponent @ react.js:7713ReactDOMComponent.Mixin.receiveComponent @ react.js:7697ReactReconciler.receiveComponent @ react.js:14131ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6884ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.receiveComponent @ react.js:6647ReactReconciler.receiveComponent @ react.js:14131ReactChildReconciler.updateChildren @ react.js:4779ReactMultiChild.Mixin._updateChildren @ react.js:12900ReactMultiChild.Mixin.updateChildren @ react.js:12874ReactDOMComponent.Mixin._updateDOMChildren @ react.js:7862ReactDOMComponent.Mixin.updateComponent @ react.js:7713ReactDOMComponent.Mixin.receiveComponent @ react.js:7697ReactReconciler.receiveComponent @ react.js:14131ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6884ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.receiveComponent @ react.js:6647ReactReconciler.receiveComponent @ react.js:14131ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6884ReactCompositeComponentMixin._performComponentUpdate @ react.js:6863ReactCompositeComponentMixin.updateComponent @ react.js:6783ReactPerf.measure.wrapper @ react.js:13371ReactCompositeComponentMixin.performUpdateIfNecessary @ react.js:6680ReactReconciler.performUpdateIfNecessary @ react.js:14149runBatchedUpdates @ react.js:14899Mixin.perform @ react.js:16625Mixin.perform @ react.js:16625assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843flushBatchedUpdates @ react.js:14923ReactPerf.measure.wrapper @ react.js:13371NESTED_UPDATES.close @ react.js:14799Mixin.closeAll @ react.js:16698Mixin.perform @ react.js:16639assign.perform @ react.js:14843

最佳答案

componentDidUpdate 内部调用 this.forceUpdate() 会导致代码中的无限递归。每次组件的 props 或状态发生变化以及调用 forceUpdate() 时,都会调用 componentDidUpdate 更新方法。因此你得到 componentDidUpdate -> forceUpdate -> componentDidUpdate -> forceUpdate -> ......[无限递归]。

要解决此问题:

  1. this.props.deck 订阅从 componentDidUpdate 移至 componentDidMount。该订阅仅需要在安装组件时添加,而不是每次更新时添加。
  2. componentDidUpdate 中删除其他 forceUpdate() 调用

关于javascript - 在 React.js 中交换元素并获取 <error>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29910504/

相关文章:

javascript - 在创建新 View 时在相似 View 上使用类而不是 id

javascript - React Hooks 中根据父组件的不同变化来更改子组件的不同 props?

javascript - 根据传递给组件的 Prop 分配样式组件 CSS 属性

javascript - 解析一串 CSS 声明并将其转换为数组

model-view-controller - Mvc前端和Mvc后端: wrong architecture?

javascript - 主干保存嵌套集合

javascript - 小部件的预填充字段

javascript - AngularJS 实现模板本地化

javascript - 没有 Wizard Gem 的 Rails 多步骤表单

javascript - 在 Javascript 中对版本点缀的数字字符串进行排序?